mirror of
https://github.com/foss42/apidash.git
synced 2025-06-28 20:13:46 +08:00
Merge branch 'add-ui-tests' of https://github.com/sixtusagbo/apidash into add-ui-tests
This commit is contained in:
12
README.md
12
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.
|
||||
|
@ -57,7 +57,7 @@ class _AppState extends ConsumerState<App> with WindowListener {
|
||||
bool isPreventClose = await windowManager.isPreventClose();
|
||||
if (isPreventClose) {
|
||||
if (ref.watch(
|
||||
settingsProvider.select((value) => value.promptBeforeClosing))) {
|
||||
settingsProvider.select((value) => value.promptBeforeClosing)) && ref.watch(hasUnsavedChangesProvider)) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
|
@ -21,7 +21,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);
|
||||
@ -403,7 +403,7 @@ const Map<String, Map<String, List<ResponseBodyView>>>
|
||||
kSubTypeDefaultViewOptions: kPreviewBodyViewOptions,
|
||||
},
|
||||
kTypeVideo: {
|
||||
kSubTypeDefaultViewOptions: kNoBodyViewOptions,
|
||||
kSubTypeDefaultViewOptions: kPreviewBodyViewOptions,
|
||||
},
|
||||
kTypeText: {
|
||||
kSubTypeDefaultViewOptions: kRawBodyViewOptions,
|
||||
@ -512,6 +512,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.";
|
||||
|
||||
|
@ -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<NameValueModel>? get enabledRequestHeaders =>
|
||||
getEnabledRows(requestHeaders, isHeaderEnabledList);
|
||||
@ -135,6 +137,7 @@ class RequestModel {
|
||||
String? message,
|
||||
ResponseModel? responseModel,
|
||||
bool? isWorking,
|
||||
DateTime? sendingTime,
|
||||
}) {
|
||||
var headers = requestHeaders ?? this.requestHeaders;
|
||||
var params = requestParams ?? this.requestParams;
|
||||
@ -160,6 +163,7 @@ class RequestModel {
|
||||
message: message ?? this.message,
|
||||
responseModel: responseModel ?? this.responseModel,
|
||||
isWorking: isWorking ?? this.isWorking,
|
||||
sendingTime: sendingTime ?? this.sendingTime,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,7 @@ class CollectionStateNotifier
|
||||
.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) {
|
||||
@ -73,6 +74,7 @@ class CollectionStateNotifier
|
||||
final itemId = itemIds.removeAt(oldIdx);
|
||||
itemIds.insert(newIdx, itemId);
|
||||
ref.read(requestSequenceProvider.notifier).state = [...itemIds];
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
void remove(String id) {
|
||||
@ -95,6 +97,7 @@ class CollectionStateNotifier
|
||||
var map = {...state!};
|
||||
map.remove(id);
|
||||
state = map;
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
void clearResponse(String? id) {
|
||||
@ -108,6 +111,7 @@ class CollectionStateNotifier
|
||||
var map = {...state!};
|
||||
map[id] = newModel;
|
||||
state = map;
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
void duplicate(String id) {
|
||||
@ -127,6 +131,7 @@ class CollectionStateNotifier
|
||||
|
||||
ref.read(requestSequenceProvider.notifier).state = [...itemIds];
|
||||
ref.read(selectedIdStateProvider.notifier).state = newId;
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
void update(
|
||||
@ -168,6 +173,7 @@ class CollectionStateNotifier
|
||||
var map = {...state!};
|
||||
map[id] = newModel;
|
||||
state = map;
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
Future<void> sendRequest(String id) async {
|
||||
@ -182,7 +188,10 @@ 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(
|
||||
@ -214,6 +223,7 @@ class CollectionStateNotifier
|
||||
map = {...state!};
|
||||
map[id] = newRequestModel;
|
||||
state = map;
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
Future<void> clearData() async {
|
||||
@ -223,6 +233,7 @@ class CollectionStateNotifier
|
||||
ref.read(clearDataStateProvider.notifier).state = false;
|
||||
ref.read(requestSequenceProvider.notifier).state = [];
|
||||
state = {};
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = true;
|
||||
}
|
||||
|
||||
bool loadData() {
|
||||
@ -263,6 +274,7 @@ class CollectionStateNotifier
|
||||
}
|
||||
await hiveHandler.removeUnused();
|
||||
ref.read(saveDataStateProvider.notifier).state = false;
|
||||
ref.read(hasUnsavedChangesProvider.notifier).state = false;
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> exportDataToHAR() async {
|
||||
|
@ -6,6 +6,8 @@ final selectedIdEditStateProvider = StateProvider<String?>((ref) => null);
|
||||
final codePaneVisibleStateProvider = StateProvider<bool>((ref) => false);
|
||||
final saveDataStateProvider = StateProvider<bool>((ref) => false);
|
||||
final clearDataStateProvider = StateProvider<bool>((ref) => false);
|
||||
final hasUnsavedChangesProvider = StateProvider<bool>((ref) => false);
|
||||
|
||||
// final nameTextFieldControllerProvider =
|
||||
// StateProvider.autoDispose<TextEditingController>((ref) {
|
||||
// TextEditingController controller = TextEditingController(text: "");
|
||||
|
@ -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(
|
||||
|
@ -12,12 +12,17 @@ class ResponsePane extends ConsumerWidget {
|
||||
final isWorking = ref.watch(
|
||||
selectedRequestModelProvider.select((value) => value?.isWorking)) ??
|
||||
false;
|
||||
final startSendingTime = 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: startSendingTime,
|
||||
);
|
||||
}
|
||||
if (responseStatus == null) {
|
||||
return const NotSentWidget();
|
||||
|
@ -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<Previewer> {
|
||||
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"
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
@ -33,18 +34,80 @@ 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<SendingWidget> createState() => _SendingWidgetState();
|
||||
}
|
||||
|
||||
class _SendingWidgetState extends State<SendingWidget> {
|
||||
int _millisecondsElapsed = 0;
|
||||
Timer? _timer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.startSendingTime != null) {
|
||||
_millisecondsElapsed =
|
||||
(DateTime.now().difference(widget.startSendingTime!).inMilliseconds ~/
|
||||
100) *
|
||||
100;
|
||||
_timer = Timer.periodic(const Duration(milliseconds: 100), _updateTimer);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateTimer(Timer timer) {
|
||||
setState(() {
|
||||
_millisecondsElapsed += 100;
|
||||
});
|
||||
}
|
||||
|
||||
@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(kAssetSendingLottie),
|
||||
],
|
||||
),
|
||||
return Stack(
|
||||
children: [
|
||||
Center(
|
||||
child: Lottie.asset(kAssetSendingLottie),
|
||||
),
|
||||
Padding(
|
||||
padding: kPh20t40,
|
||||
child: Visibility(
|
||||
visible: _millisecondsElapsed >= 0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.alarm,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
Text(
|
||||
'Time elapsed: ${humanizeDuration(Duration(milliseconds: _millisecondsElapsed))}',
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
style: kTextStyleButton.copyWith(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
147
lib/widgets/video_previewer.dart
Normal file
147
lib/widgets/video_previewer.dart
Normal file
@ -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<VideoPreviewer> createState() => _VideoPreviewerState();
|
||||
}
|
||||
|
||||
class _VideoPreviewerState extends State<VideoPreviewer> {
|
||||
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}');
|
||||
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();
|
||||
}
|
||||
}
|
64
pubspec.lock
64
pubspec.lock
@ -225,6 +225,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:
|
||||
@ -504,6 +512,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:
|
||||
@ -552,6 +568,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:
|
||||
@ -1350,6 +1374,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:
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -10,13 +10,15 @@ 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,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -24,6 +26,26 @@ void main() {
|
||||
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(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
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 {
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
|
Reference in New Issue
Block a user