From ea53b46826f79c72e3e1aa61c6d795481d60f705 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 23 Jul 2024 13:13:39 +0300 Subject: [PATCH 01/42] Add JavaScript channels for peer connection and chunk download events --- assets/vidstack_player.html | 15 ++++++++++++++- lib/demo/vidstack_player.dart | 28 +++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index f5356b3..a383d9f 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -47,8 +47,21 @@ }, onHlsJsCreated: (hls) => { hls.p2pEngine.addEventListener("onPeerConnect", (params) => { - console.log("Peer connected:", params.peerId); + window.flutter_inappwebview.callHandler( + "onPeerConnect", + params + ); }); + + hls.p2pEngine.addEventListener( + "onChunkDownloaded", + (params) => { + window.flutter_inappwebview.callHandler( + "onChunkDownloaded", + params + ); + } + ); }, }, }; diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index b6b525c..05cfed5 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; @@ -13,11 +15,14 @@ class VidstackPlayer extends StatefulWidget { class _VidstackPlayerState extends State { late final WebViewController controller; final double aspectRatio = 16 / 9; + List activePeers = []; + double chunkCount = 0; @override void initState() { super.initState(); late final PlatformWebViewControllerCreationParams params; + if (WebViewPlatform.instance is WebKitWebViewPlatform) { params = WebKitWebViewControllerCreationParams( allowsInlineMediaPlayback: true, @@ -28,12 +33,30 @@ class _VidstackPlayerState extends State { } controller = WebViewController.fromPlatformCreationParams(params) - ..setJavaScriptMode(JavaScriptMode.unrestricted); + ..setJavaScriptMode(JavaScriptMode.unrestricted) + ..addJavaScriptChannel("onPeerConnected", + onMessageReceived: (JavaScriptMessage msg) { + final msgData = jsonDecode(msg.message) as Map; + final String peerToAdd = msgData['peerId'] ?? ''; + + if (peerToAdd.isEmpty) return; + + setState(() { + activePeers.add(peerToAdd); + }); + }) + ..addJavaScriptChannel("onChunkDownloaded", + onMessageReceived: (JavaScriptMessage msg) { + setState(() { + chunkCount++; + }); + }); var platform = controller.platform; if (platform is AndroidWebViewController) { platform.setMediaPlaybackRequiresUserGesture(false); + AndroidWebViewController.enableDebugging(true); } controller.loadFlutterAsset('assets/vidstack_player.html'); @@ -59,6 +82,9 @@ class _VidstackPlayerState extends State { ), ), const SizedBox(height: 20), + Text('Active Peers: ${activePeers.join(', ')}'), + Text('Chunk Count: $chunkCount'), + const SizedBox(height: 20), ElevatedButton( onPressed: () { // Handle button press From 4793cc83be231c492210dfb941fe5f8188286cac Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 23 Jul 2024 14:29:16 +0300 Subject: [PATCH 02/42] Test onPeerConnected event --- assets/vidstack_player.html | 17 ++--------------- lib/demo/vidstack_player.dart | 11 +++-------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index a383d9f..a81c91d 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -43,25 +43,12 @@ provider.config = { p2p: { core: { - swarmId: "Optional custom swarm ID for stream", + // swarmId: "Optional custom swarm ID for stream", }, onHlsJsCreated: (hls) => { hls.p2pEngine.addEventListener("onPeerConnect", (params) => { - window.flutter_inappwebview.callHandler( - "onPeerConnect", - params - ); + onPeerConnect.postMessage(JSON.stringify(params)); }); - - hls.p2pEngine.addEventListener( - "onChunkDownloaded", - (params) => { - window.flutter_inappwebview.callHandler( - "onChunkDownloaded", - params - ); - } - ); }, }, }; diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index 05cfed5..ea50ea9 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -44,19 +44,12 @@ class _VidstackPlayerState extends State { setState(() { activePeers.add(peerToAdd); }); - }) - ..addJavaScriptChannel("onChunkDownloaded", - onMessageReceived: (JavaScriptMessage msg) { - setState(() { - chunkCount++; - }); }); var platform = controller.platform; if (platform is AndroidWebViewController) { platform.setMediaPlaybackRequiresUserGesture(false); - AndroidWebViewController.enableDebugging(true); } controller.loadFlutterAsset('assets/vidstack_player.html'); @@ -87,7 +80,9 @@ class _VidstackPlayerState extends State { const SizedBox(height: 20), ElevatedButton( onPressed: () { - // Handle button press + setState(() { + chunkCount++; + }); }, child: const Text('Click Me'), ), From f3b86842355562d56cace4cc2880ad22934ac399 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 23 Jul 2024 14:54:39 +0300 Subject: [PATCH 03/42] Add event listeners for peer connection and chunk download events --- assets/vidstack_player.html | 11 +++++++++++ lib/demo/vidstack_player.dart | 37 +++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index a81c91d..ba5c2ca 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -49,6 +49,17 @@ hls.p2pEngine.addEventListener("onPeerConnect", (params) => { onPeerConnect.postMessage(JSON.stringify(params)); }); + + hls.p2pEngine.addEventListener("onPeerClose", (params) => { + onPeerClose.postMessage(JSON.stringify(params)); + }); + + hls.p2pEngine.addEventListener( + "onChunkDownloaded", + (params) => { + onChunkDownloaded.postMessage(JSON.stringify(params)); + } + ); }, }, }; diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index ea50ea9..55f874c 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -1,10 +1,13 @@ import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart'; +double convertToMiB(double bytes) { + return bytes / 1024 / 1024; +} + class VidstackPlayer extends StatefulWidget { const VidstackPlayer({super.key}); @@ -17,6 +20,8 @@ class _VidstackPlayerState extends State { final double aspectRatio = 16 / 9; List activePeers = []; double chunkCount = 0; + double totalHttpDownloaded = 0; + double totalP2PDownloaded = 0; @override void initState() { @@ -44,6 +49,33 @@ class _VidstackPlayerState extends State { setState(() { activePeers.add(peerToAdd); }); + }) + ..addJavaScriptChannel("onPeerClose", + onMessageReceived: (JavaScriptMessage msg) { + final msgData = jsonDecode(msg.message) as Map; + final String peerToRemove = msgData['peerId'] ?? ''; + + if (peerToRemove.isEmpty) return; + + setState(() { + activePeers.remove(peerToRemove); + }); + }) + ..addJavaScriptChannel("onChunkDownloaded", + onMessageReceived: (JavaScriptMessage msg) { + final msgData = jsonDecode(msg.message) as Map; + final double loadedBytes = msgData['bytesLength'] ?? 0; + final String downloadSource = msgData['downloadSource'] ?? ''; + + if (downloadSource == 'http') { + setState(() { + totalHttpDownloaded += convertToMiB(loadedBytes); + }); + } else if (downloadSource == 'p2p') { + setState(() { + totalP2PDownloaded += convertToMiB(loadedBytes); + }); + } }); var platform = controller.platform; @@ -76,7 +108,8 @@ class _VidstackPlayerState extends State { ), const SizedBox(height: 20), Text('Active Peers: ${activePeers.join(', ')}'), - Text('Chunk Count: $chunkCount'), + Text( + 'Downloaded through HTTP: ${totalHttpDownloaded.toStringAsFixed(2)} MiB'), const SizedBox(height: 20), ElevatedButton( onPressed: () { From 424d3ab0137b25833347ec9b3c21421f5e9e9179 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 23 Jul 2024 15:39:31 +0300 Subject: [PATCH 04/42] Refactor VidstackPlayer component and add event listeners for peer connection and chunk download events --- assets/vidstack_player.html | 6 +- lib/demo/vidstack_player.dart | 111 ++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 53 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index ba5c2ca..597750e 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -56,7 +56,11 @@ hls.p2pEngine.addEventListener( "onChunkDownloaded", - (params) => { + (bytesLength, downloadSource) => { + const params = { + bytesLength, + downloadSource, + }; onChunkDownloaded.postMessage(JSON.stringify(params)); } ); diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index 55f874c..c5cf271 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -4,6 +4,7 @@ import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart'; +// Helper function to convert bytes to MiB double convertToMiB(double bytes) { return bytes / 1024 / 1024; } @@ -19,13 +20,17 @@ class _VidstackPlayerState extends State { late final WebViewController controller; final double aspectRatio = 16 / 9; List activePeers = []; - double chunkCount = 0; double totalHttpDownloaded = 0; double totalP2PDownloaded = 0; @override void initState() { super.initState(); + _initializeWebViewController(); + controller.loadFlutterAsset('assets/vidstack_player.html'); + } + + void _initializeWebViewController() { late final PlatformWebViewControllerCreationParams params; if (WebViewPlatform.instance is WebKitWebViewPlatform) { @@ -40,51 +45,52 @@ class _VidstackPlayerState extends State { controller = WebViewController.fromPlatformCreationParams(params) ..setJavaScriptMode(JavaScriptMode.unrestricted) ..addJavaScriptChannel("onPeerConnected", - onMessageReceived: (JavaScriptMessage msg) { - final msgData = jsonDecode(msg.message) as Map; - final String peerToAdd = msgData['peerId'] ?? ''; - - if (peerToAdd.isEmpty) return; - - setState(() { - activePeers.add(peerToAdd); - }); - }) - ..addJavaScriptChannel("onPeerClose", - onMessageReceived: (JavaScriptMessage msg) { - final msgData = jsonDecode(msg.message) as Map; - final String peerToRemove = msgData['peerId'] ?? ''; - - if (peerToRemove.isEmpty) return; - - setState(() { - activePeers.remove(peerToRemove); - }); - }) + onMessageReceived: _onPeerConnected) + ..addJavaScriptChannel("onPeerClose", onMessageReceived: _onPeerClose) ..addJavaScriptChannel("onChunkDownloaded", - onMessageReceived: (JavaScriptMessage msg) { - final msgData = jsonDecode(msg.message) as Map; - final double loadedBytes = msgData['bytesLength'] ?? 0; - final String downloadSource = msgData['downloadSource'] ?? ''; - - if (downloadSource == 'http') { - setState(() { - totalHttpDownloaded += convertToMiB(loadedBytes); - }); - } else if (downloadSource == 'p2p') { - setState(() { - totalP2PDownloaded += convertToMiB(loadedBytes); - }); - } - }); + onMessageReceived: _onChunkDownloaded); var platform = controller.platform; if (platform is AndroidWebViewController) { platform.setMediaPlaybackRequiresUserGesture(false); } + } - controller.loadFlutterAsset('assets/vidstack_player.html'); + void _onPeerConnected(JavaScriptMessage msg) { + final msgData = jsonDecode(msg.message) as Map; + final String peerToAdd = msgData['peerId'] ?? ''; + + if (peerToAdd.isEmpty) return; + + setState(() { + activePeers.add(peerToAdd); + }); + } + + void _onPeerClose(JavaScriptMessage msg) { + final msgData = jsonDecode(msg.message) as Map; + final String peerToRemove = msgData['peerId'] ?? ''; + + if (peerToRemove.isEmpty) return; + + setState(() { + activePeers.remove(peerToRemove); + }); + } + + void _onChunkDownloaded(JavaScriptMessage msg) { + final msgData = jsonDecode(msg.message) as Map; + final double loadedBytes = (msgData['bytesLength'] ?? 0).toDouble(); + final String downloadSource = msgData['downloadSource'] ?? ''; + + setState(() { + if (downloadSource == 'http') { + totalHttpDownloaded += convertToMiB(loadedBytes); + } else if (downloadSource == 'p2p') { + totalP2PDownloaded += convertToMiB(loadedBytes); + } + }); } @override @@ -102,26 +108,27 @@ class _VidstackPlayerState extends State { SizedBox( width: webViewWidth, height: webViewHeight, - child: WebViewWidget( - controller: controller, - ), + child: WebViewWidget(controller: controller), ), const SizedBox(height: 20), - Text('Active Peers: ${activePeers.join(', ')}'), - Text( - 'Downloaded through HTTP: ${totalHttpDownloaded.toStringAsFixed(2)} MiB'), + _buildInfoText(), const SizedBox(height: 20), - ElevatedButton( - onPressed: () { - setState(() { - chunkCount++; - }); - }, - child: const Text('Click Me'), - ), ], ), ), ); } + + Widget _buildInfoText() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Active Peers: ${activePeers.join(', ')}'), + Text( + 'Downloaded through HTTP: ${totalHttpDownloaded.toStringAsFixed(2)} MiB'), + Text( + 'Downloaded through P2P: ${totalP2PDownloaded.toStringAsFixed(2)} MiB'), + ], + ); + } } From 943e6aaee7e222d406a92a5f90a5dab7e10c9c5e Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 23 Jul 2024 15:52:56 +0300 Subject: [PATCH 05/42] Refactor type parsing from JSON --- lib/demo/vidstack_player.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index c5cf271..96a5564 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; @@ -59,9 +60,9 @@ class _VidstackPlayerState extends State { void _onPeerConnected(JavaScriptMessage msg) { final msgData = jsonDecode(msg.message) as Map; - final String peerToAdd = msgData['peerId'] ?? ''; + final peerToAdd = msgData['peerId'] as String?; - if (peerToAdd.isEmpty) return; + if (peerToAdd == null) return; setState(() { activePeers.add(peerToAdd); @@ -70,9 +71,9 @@ class _VidstackPlayerState extends State { void _onPeerClose(JavaScriptMessage msg) { final msgData = jsonDecode(msg.message) as Map; - final String peerToRemove = msgData['peerId'] ?? ''; + final peerToRemove = msgData['peerId'] as String?; - if (peerToRemove.isEmpty) return; + if (peerToRemove == null) return; setState(() { activePeers.remove(peerToRemove); @@ -81,8 +82,10 @@ class _VidstackPlayerState extends State { void _onChunkDownloaded(JavaScriptMessage msg) { final msgData = jsonDecode(msg.message) as Map; - final double loadedBytes = (msgData['bytesLength'] ?? 0).toDouble(); - final String downloadSource = msgData['downloadSource'] ?? ''; + final loadedBytes = msgData['bytesLength'] as double?; + final downloadSource = msgData['downloadSource'] as String?; + + if (loadedBytes == null || downloadSource == null) return; setState(() { if (downloadSource == 'http') { From d1f0ff60f0090cab4ad1b6215ef760094bf993ef Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 23 Jul 2024 16:13:19 +0300 Subject: [PATCH 06/42] Small improvements --- lib/demo/vidstack_player.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index 96a5564..f41b8e1 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -1,11 +1,9 @@ import 'dart:convert'; -import 'dart:ffi'; import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; import 'package:webview_flutter_android/webview_flutter_android.dart'; import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart'; -// Helper function to convert bytes to MiB double convertToMiB(double bytes) { return bytes / 1024 / 1024; } From 46aa7ca0c8ba7d7bb6d0de5d9cfa354365d0d68d Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 23 Jul 2024 16:42:35 +0300 Subject: [PATCH 07/42] Improve error handling in VidstackPlayer component --- lib/demo/vidstack_player.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index f41b8e1..dc43e2c 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -60,7 +60,7 @@ class _VidstackPlayerState extends State { final msgData = jsonDecode(msg.message) as Map; final peerToAdd = msgData['peerId'] as String?; - if (peerToAdd == null) return; + if (peerToAdd == null || peerToAdd.isEmpty) return; setState(() { activePeers.add(peerToAdd); @@ -71,7 +71,7 @@ class _VidstackPlayerState extends State { final msgData = jsonDecode(msg.message) as Map; final peerToRemove = msgData['peerId'] as String?; - if (peerToRemove == null) return; + if (peerToRemove == null || peerToRemove.isEmpty) return; setState(() { activePeers.remove(peerToRemove); @@ -79,8 +79,11 @@ class _VidstackPlayerState extends State { } void _onChunkDownloaded(JavaScriptMessage msg) { - final msgData = jsonDecode(msg.message) as Map; - final loadedBytes = msgData['bytesLength'] as double?; + final msgData = jsonDecode(msg.message) as Map?; + + if (msgData == null) return; + + final loadedBytes = (msgData['bytesLength'] as num?)?.toDouble(); final downloadSource = msgData['downloadSource'] as String?; if (loadedBytes == null || downloadSource == null) return; From 36bf4e9e810a1a6c08b78a6f5a434e3119afd0f6 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Wed, 24 Jul 2024 11:07:48 +0300 Subject: [PATCH 08/42] Add P2P download and upload statistics to VidstackPlayer --- assets/vidstack_player.html | 58 +++++++++++++++++++++++++++++------ lib/demo/vidstack_player.dart | 29 ++++++++++++------ 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index 597750e..bfc6720 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -31,20 +31,36 @@ diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index dc43e2c..ec7a002 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -21,6 +21,7 @@ class _VidstackPlayerState extends State { List activePeers = []; double totalHttpDownloaded = 0; double totalP2PDownloaded = 0; + double totalP2PUploaded = 0; @override void initState() { @@ -47,7 +48,9 @@ class _VidstackPlayerState extends State { onMessageReceived: _onPeerConnected) ..addJavaScriptChannel("onPeerClose", onMessageReceived: _onPeerClose) ..addJavaScriptChannel("onChunkDownloaded", - onMessageReceived: _onChunkDownloaded); + onMessageReceived: _onChunkDownloaded) + ..addJavaScriptChannel("onChunkUploaded", + onMessageReceived: _onChunkUploaded); var platform = controller.platform; @@ -56,6 +59,17 @@ class _VidstackPlayerState extends State { } } + void _onChunkUploaded(JavaScriptMessage msg) { + final msgData = jsonDecode(msg.message) as Map; + final uploadedBytes = (msgData['uploadedBytes'] as num?)?.toDouble(); + + if (uploadedBytes == null) return; + + setState(() { + totalP2PUploaded += convertToMiB(uploadedBytes); + }); + } + void _onPeerConnected(JavaScriptMessage msg) { final msgData = jsonDecode(msg.message) as Map; final peerToAdd = msgData['peerId'] as String?; @@ -79,20 +93,17 @@ class _VidstackPlayerState extends State { } void _onChunkDownloaded(JavaScriptMessage msg) { - final msgData = jsonDecode(msg.message) as Map?; - - if (msgData == null) return; - - final loadedBytes = (msgData['bytesLength'] as num?)?.toDouble(); + final msgData = jsonDecode(msg.message) as Map; + final downloadedBytes = (msgData['downloadedBytes'] as num?)?.toDouble(); final downloadSource = msgData['downloadSource'] as String?; - if (loadedBytes == null || downloadSource == null) return; + if (downloadedBytes == null || downloadSource == null) return; setState(() { if (downloadSource == 'http') { - totalHttpDownloaded += convertToMiB(loadedBytes); + totalHttpDownloaded += convertToMiB(downloadedBytes); } else if (downloadSource == 'p2p') { - totalP2PDownloaded += convertToMiB(loadedBytes); + totalP2PDownloaded += convertToMiB(downloadedBytes); } }); } From 5af58c41534f911b34e53f8ce18700b01251b2b8 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Wed, 24 Jul 2024 11:47:03 +0300 Subject: [PATCH 09/42] Refactor VidstackPlayer component and add P2P download and upload statistics --- lib/demo/vidstack_player.dart | 57 +++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index ec7a002..fa4bc11 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -115,7 +115,7 @@ class _VidstackPlayerState extends State { return Scaffold( appBar: AppBar( - title: const Text('Demo Component'), + title: const Text('Vidstack Player'), ), body: SingleChildScrollView( child: Column( @@ -126,7 +126,7 @@ class _VidstackPlayerState extends State { child: WebViewWidget(controller: controller), ), const SizedBox(height: 20), - _buildInfoText(), + _buildInfoCards(), const SizedBox(height: 20), ], ), @@ -134,16 +134,49 @@ class _VidstackPlayerState extends State { ); } - Widget _buildInfoText() { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Active Peers: ${activePeers.join(', ')}'), - Text( - 'Downloaded through HTTP: ${totalHttpDownloaded.toStringAsFixed(2)} MiB'), - Text( - 'Downloaded through P2P: ${totalP2PDownloaded.toStringAsFixed(2)} MiB'), - ], + Widget _buildInfoCards() { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + children: [ + _buildCard( + title: 'Downloaded through HTTP', + content: '${totalHttpDownloaded.toStringAsFixed(2)} MiB', + icon: Icons.download, + ), + const SizedBox(height: 10), + _buildCard( + title: 'Downloaded through P2P', + content: '${totalP2PDownloaded.toStringAsFixed(2)} MiB', + icon: Icons.cloud_download, + ), + const SizedBox(height: 10), + _buildCard( + title: 'Uploaded through P2P', + content: '${totalP2PUploaded.toStringAsFixed(2)} MiB', + icon: Icons.cloud_upload, + ), + const SizedBox(height: 10), + _buildCard( + title: 'Active Peers', + content: activePeers.length.toString(), + icon: Icons.group, + ), + ], + ), + ); + } + + Widget _buildCard( + {required String title, + required String content, + required IconData icon}) { + return Card( + child: ListTile( + leading: Icon(icon, color: Theme.of(context).primaryColor), + title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), + subtitle: Text(content), + ), ); } } From 0c513eccf51b5b0634fc88bd29f7b59e95543ead Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Thu, 25 Jul 2024 11:23:49 +0300 Subject: [PATCH 10/42] Update JavaScript channel name for peer connection event --- lib/demo/vidstack_player.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/demo/vidstack_player.dart b/lib/demo/vidstack_player.dart index fa4bc11..44f6b7c 100644 --- a/lib/demo/vidstack_player.dart +++ b/lib/demo/vidstack_player.dart @@ -44,7 +44,7 @@ class _VidstackPlayerState extends State { controller = WebViewController.fromPlatformCreationParams(params) ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..addJavaScriptChannel("onPeerConnected", + ..addJavaScriptChannel("onPeerConnect", onMessageReceived: _onPeerConnected) ..addJavaScriptChannel("onPeerClose", onMessageReceived: _onPeerClose) ..addJavaScriptChannel("onChunkDownloaded", From 79cf17108f4ecde37cb61818b6ee8a6bfb9a3c09 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Fri, 26 Jul 2024 12:29:04 +0300 Subject: [PATCH 11/42] Add P2P functionality to VidstackPlayer component --- assets/vidstack_player.html | 31 +++++++++++++++++++++++++++- lib/demo/vidstack_player.dart | 38 ++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index bfc6720..37107bf 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -31,6 +31,33 @@ - - - + + From e5d1733a9579ca80f71e1df670edaefc77c22505 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Fri, 26 Jul 2024 14:08:25 +0300 Subject: [PATCH 13/42] Stylesheet moved upper --- assets/vidstack_player.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index 938a3f6..f98c417 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -3,6 +3,9 @@ + + + - - - - + -
- - - - -
+
diff --git a/lib/screens/demo_screen.dart b/lib/screens/demo_screen.dart index 56fe1f9..d4c4261 100644 --- a/lib/screens/demo_screen.dart +++ b/lib/screens/demo_screen.dart @@ -10,10 +10,10 @@ class VidstackPlayerScreen extends StatefulWidget { } class _VidstackPlayerScreenState extends State { + final Set _activePeers = {}; double _totalHttpDownloaded = 0; double _totalP2PDownloaded = 0; double _totalP2PUploaded = 0; - final Set _activePeers = {}; void _updateHttpDownloadStats(double httpDownloaded) { setState(() { From 18ad00bbbc7ea53a10af925b6b4827dd8dabfcd1 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Fri, 2 Aug 2024 00:37:12 -0700 Subject: [PATCH 23/42] Update Vidstack player initialization --- assets/vidstack_player.html | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/assets/vidstack_player.html b/assets/vidstack_player.html index 254b910..9a0b3c4 100644 --- a/assets/vidstack_player.html +++ b/assets/vidstack_player.html @@ -10,18 +10,15 @@ - diff --git a/lib/p2p_webview_demo/vidstack_player_webview.dart b/lib/p2p_webview_demo/vidstack_player_webview.dart index ae993a5..af4c8d3 100644 --- a/lib/p2p_webview_demo/vidstack_player_webview.dart +++ b/lib/p2p_webview_demo/vidstack_player_webview.dart @@ -28,25 +28,7 @@ class VidstackWebView extends StatefulWidget { } class _VidstackWebViewState extends State { - late InAppWebViewController? _controller; - - @override - void dispose() { - _destroyP2P(); - _cleanUpWebView(); - super.dispose(); - } - - void _cleanUpWebView() { - _controller?.removeJavaScriptHandler(handlerName: 'onPeerConnect'); - _controller?.removeJavaScriptHandler(handlerName: 'onPeerClose'); - _controller?.removeJavaScriptHandler(handlerName: 'onChunkDownloaded'); - _controller?.removeJavaScriptHandler(handlerName: 'onChunkUploaded'); - _controller?.dispose(); - } - void _initializeWebViewController(InAppWebViewController controller) { - _controller = controller; _applyJavaScriptHandlers(controller); controller.loadFile(assetFilePath: widget.assetPath); } @@ -98,10 +80,6 @@ class _VidstackWebViewState extends State { widget.onChunkUploaded?.call(convertToMiB(uploadedBytes)); } - void _destroyP2P() { - _controller?.evaluateJavascript(source: "window.destroyP2P()"); - } - @override Widget build(BuildContext context) { return AspectRatio( From 5ee03e0079a8a20289e56d453b9ec9d5cbf43e83 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Mon, 12 Aug 2024 10:13:12 +0300 Subject: [PATCH 34/42] Add test build workflow --- .github/workflows/build.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..b98a914 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,30 @@ +name: "Build" + +on: + pull_request: + branches: + - dev + push: + branches: + - dev + +jobs: + build: + runs-on: macos-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Flutter + uses: subosito/flutter-action@v2 + with: + channel: "stable" + + - run: flutter --version + + - name: Get dependencies + run: flutter pub get + + - name: Build + run: flutter build ios --release --no-codesign From 7e347d9c73909bf44d15e806b71cfc7b9c50fd76 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Mon, 12 Aug 2024 10:27:22 +0300 Subject: [PATCH 35/42] Update build workflow to include iOS and Android builds --- .github/workflows/build.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b98a914..0130e1f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,12 +1,13 @@ -name: "Build" +name: "Build IOS & Android" on: pull_request: branches: - - dev + - main push: branches: - dev + - main jobs: build: @@ -23,8 +24,14 @@ jobs: - run: flutter --version + - name: Flutter analyze + run: flutter analyze + - name: Get dependencies run: flutter pub get - - name: Build + - name: Build IOS run: flutter build ios --release --no-codesign + + - name: Build Android + run: flutter build apk --release From 7f87a65f861b20ad55bf16fc1b87df9256397112 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Mon, 12 Aug 2024 10:41:41 +0300 Subject: [PATCH 36/42] Update build workflow to include iOS and Android builds --- .github/workflows/build.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0130e1f..ecea01a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,10 +4,6 @@ on: pull_request: branches: - main - push: - branches: - - dev - - main jobs: build: @@ -33,5 +29,11 @@ jobs: - name: Build IOS run: flutter build ios --release --no-codesign + - name: Set Up Java + uses: actions/setup-java@v4 + with: + distribution: "oracle" + java-version: "21" + - name: Build Android run: flutter build apk --release From 49cfce524557678556358f52eda51b2ab87ac894 Mon Sep 17 00:00:00 2001 From: Dmytro Demchenko Date: Mon, 12 Aug 2024 10:47:59 +0300 Subject: [PATCH 37/42] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ecea01a..d6610a1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ jobs: uses: actions/setup-java@v4 with: distribution: "oracle" - java-version: "21" + java-version: "17" - name: Build Android run: flutter build apk --release From f98a4b105cd6cdcb37e9fca12b35870b357d04c8 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Mon, 12 Aug 2024 16:19:24 +0300 Subject: [PATCH 38/42] Update Java and Gradle versions for build workflow --- .github/workflows/build.yml | 14 ++++++-------- android/app/build.gradle | 8 ++++++-- android/gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6610a1..2ac9c6b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,13 +13,17 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Set Up Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "17" + - name: Setup Flutter uses: subosito/flutter-action@v2 with: channel: "stable" - - run: flutter --version - - name: Flutter analyze run: flutter analyze @@ -29,11 +33,5 @@ jobs: - name: Build IOS run: flutter build ios --release --no-codesign - - name: Set Up Java - uses: actions/setup-java@v4 - with: - distribution: "oracle" - java-version: "17" - - name: Build Android run: flutter build apk --release diff --git a/android/app/build.gradle b/android/app/build.gradle index 371a043..2ce304f 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -29,8 +29,12 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.toVersion("17") + targetCompatibility = JavaVersion.toVersion("17") + } + + kotlinOptions { + jvmTarget = "17" } defaultConfig { diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index e1ca574..7bb2df6 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip From 527d359cdac3158a0a5d0c8d64b4519d86c276c5 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 13 Aug 2024 10:50:20 +0300 Subject: [PATCH 39/42] Update build workflow to use Ubuntu and OpenJDK 17 --- .github/workflows/build.yml | 12 +++--------- android/gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ac9c6b..cfb8dc0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,4 +1,4 @@ -name: "Build IOS & Android" +name: "Build apk" on: pull_request: @@ -7,7 +7,7 @@ on: jobs: build: - runs-on: macos-latest + runs-on: ubuntu-latest steps: - name: Checkout @@ -16,7 +16,7 @@ jobs: - name: Set Up Java uses: actions/setup-java@v4 with: - distribution: "temurin" + distribution: "openjdk" java-version: "17" - name: Setup Flutter @@ -24,14 +24,8 @@ jobs: with: channel: "stable" - - name: Flutter analyze - run: flutter analyze - - name: Get dependencies run: flutter pub get - - name: Build IOS - run: flutter build ios --release --no-codesign - - name: Build Android run: flutter build apk --release diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 7bb2df6..e1ca574 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip From be0d8ffe3cc8718660fbe21c0f0559c9c087a72c Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 13 Aug 2024 10:57:34 +0300 Subject: [PATCH 40/42] Update build workflow to use Oracle JDK 17 and Flutter stable version --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfb8dc0..b9f0e4f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,13 +16,14 @@ jobs: - name: Set Up Java uses: actions/setup-java@v4 with: - distribution: "openjdk" + distribution: "oracle" java-version: "17" - name: Setup Flutter uses: subosito/flutter-action@v2 with: channel: "stable" + flutter-version-file: pubspec.yaml - name: Get dependencies run: flutter pub get From a7692de5f21c09337b7be8e3497798f9cfa73a4f Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 13 Aug 2024 11:02:39 +0300 Subject: [PATCH 41/42] Update build workflow to use Flutter stable version --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9f0e4f..2558466 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,6 @@ jobs: uses: subosito/flutter-action@v2 with: channel: "stable" - flutter-version-file: pubspec.yaml - name: Get dependencies run: flutter pub get From 215f3b641347c51d645f1933efc0adb96f0e2c83 Mon Sep 17 00:00:00 2001 From: DimaDemchenko Date: Tue, 13 Aug 2024 13:23:17 +0300 Subject: [PATCH 42/42] Update Android Gradle plugin version to 7.4.2 --- android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/settings.gradle b/android/settings.gradle index 536165d..9b1a101 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false + id "com.android.application" version "7.4.2" apply false id "org.jetbrains.kotlin.android" version "1.7.10" apply false }