Merge pull request #315 from mdrazak2001/video-preview-hotfix

add video preview with updated logic
This commit is contained in:
Ankit Mahato
2024-03-28 21:16:21 +05:30
committed by GitHub
6 changed files with 228 additions and 7 deletions

View File

@ -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.";

View File

@ -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"

View 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();
}
}

View File

@ -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:

View File

@ -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

View File

@ -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 {