From 7a3357ab13b36643e8816af92a888e1504b3f4ca Mon Sep 17 00:00:00 2001 From: ge59dil Date: Wed, 24 Jan 2024 21:25:58 +0100 Subject: [PATCH 1/8] Adding download over wifi func --- lib/view_models/download_view_model.dart | 18 +++++++++++- lib/views/video_view/video_player.dart | 36 ++++++++++++++++++------ pubspec.lock | 24 ++++++++++++++++ pubspec.yaml | 1 + 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index dac7b370..422e6a55 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fixnum/fixnum.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -9,6 +10,7 @@ import 'dart:io'; import '../models/download_state_model.dart'; class DownloadViewModel extends StateNotifier { + final Logger _logger = Logger(); DownloadViewModel() : super(const DownloadState()) { @@ -26,9 +28,23 @@ class DownloadViewModel extends StateNotifier { } } + Future isConnectedToWifi() async { + var connectivityResult = await (Connectivity().checkConnectivity()); + if (connectivityResult == ConnectivityResult.wifi) { + return true; + } else { + return false; + } + } + Future downloadVideo( - String videoUrl, Int64 streamId, String fileName,) async { + String videoUrl, Int64 streamId, String fileName,{required bool downloadOverWifiOnly,}) async { try { + // Check if 'Download Over Wi-Fi Only' is enabled and if not connected to Wi-Fi + if (downloadOverWifiOnly && !(await isConnectedToWifi())) { + _logger.w('Not connected to Wi-Fi. Download cancelled.'); + throw Exception('Not connected to Wi-Fi'); + } final directory = await getApplicationDocumentsDirectory(); final filePath = '${directory.path}/$fileName'; Dio dio = Dio(); diff --git a/lib/views/video_view/video_player.dart b/lib/views/video_view/video_player.dart index fe184a3c..52f7bc41 100644 --- a/lib/views/video_view/video_player.dart +++ b/lib/views/video_view/video_player.dart @@ -235,8 +235,9 @@ class VideoPlayerPageState extends ConsumerState { _isChatVisible = !_isChatVisible; }); } - void _downloadVideo(Stream stream) { + final isDownloadWithWifiOnly = ref.watch(settingViewModelProvider).isDownloadWithWifiOnly; + // Extract the "Combined" download URL from the Stream object String? combinedDownloadUrl; for (var download in stream.downloads) { @@ -245,7 +246,7 @@ class VideoPlayerPageState extends ConsumerState { break; } } - //combinedDownloadUrl="https://file-examples.com/storage/fe5048eb7365a64ba96daa9/2017/04/file_example_MP4_480_1_5MG.mp4"; + // Check if the Combined URL is found if (combinedDownloadUrl == null) { ScaffoldMessenger.of(context).showSnackBar( @@ -257,16 +258,35 @@ class VideoPlayerPageState extends ConsumerState { // Use the extracted URL for downloading String fileName = "stream.mp4"; ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Downloading Video')), + const SnackBar(content: Text('Starting download...')), ); - // Call the download function from the StreamViewModel + + // Call the download function from the DownloadViewModel ref .read(downloadViewModelProvider.notifier) - .downloadVideo(combinedDownloadUrl, stream.id, fileName) + .downloadVideo(combinedDownloadUrl, stream.id, fileName, downloadOverWifiOnly: isDownloadWithWifiOnly) .then((localPath) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Video Downloaded')), - ); + if (localPath.isNotEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Video Downloaded')), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Download failed')), + ); + } + }).catchError((error) { + // Handle specific error from 'downloadVideo' + if (error.toString() == 'Exception: Not connected to Wi-Fi') { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Please connect to Wi-Fi to download videos')), + ); + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Error: ${error.toString()}')), + ); + } }); } + } diff --git a/pubspec.lock b/pubspec.lock index ca00702d..69d90b5a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -81,6 +81,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + sha256: "224a77051d52a11fbad53dd57827594d3bd24f945af28bd70bab376d68d437f0" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + sha256: cf1d1c28f4416f8c654d7dc3cd638ec586076255d407cef3ddbdaf178272a71a + url: "https://pub.dev" + source: hosted + version: "1.2.4" convert: dependency: transitive description: @@ -424,6 +440,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254" + url: "https://pub.dev" + source: hosted + version: "0.5.0" package_info_plus: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index cbb9823d..fb132521 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,6 +7,7 @@ environment: sdk: '>=3.1.5 <4.0.0' dependencies: + connectivity_plus: ^5.0.2 bloc: ^8.1.2 cookie_jar: ^4.0.8 dio_cookie_manager: ^3.1.1 From 6d1fb739a308c8f0804d810b5d190b00af2e60d2 Mon Sep 17 00:00:00 2001 From: ge59dil Date: Wed, 24 Jan 2024 21:48:05 +0100 Subject: [PATCH 2/8] download over wifi func --- android/app/src/main/AndroidManifest.xml | 1 + ios/Podfile.lock | 10 ++++++++++ ios/Runner/Info.plist | 4 ++++ lib/view_models/download_view_model.dart | 5 ++++- lib/views/video_view/video_player.dart | 2 +- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index cbf99b2e..5d939348 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,5 @@ + +NSLocationWhenInUseUsageDescription +This app needs location access to determine your Wi-Fi network +NSLocationAlwaysUsageDescription +This app needs location access to determine your Wi-Fi network CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index 422e6a55..3c4f0d08 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -40,8 +40,11 @@ class DownloadViewModel extends StateNotifier { Future downloadVideo( String videoUrl, Int64 streamId, String fileName,{required bool downloadOverWifiOnly,}) async { try { + _logger.d('Download Over Wi-Fi Only setting is: $downloadOverWifiOnly'); + + // Check if 'Download Over Wi-Fi Only' is enabled and if not connected to Wi-Fi - if (downloadOverWifiOnly && !(await isConnectedToWifi())) { + if (downloadOverWifiOnly == (await isConnectedToWifi())) { _logger.w('Not connected to Wi-Fi. Download cancelled.'); throw Exception('Not connected to Wi-Fi'); } diff --git a/lib/views/video_view/video_player.dart b/lib/views/video_view/video_player.dart index 52f7bc41..651145ba 100644 --- a/lib/views/video_view/video_player.dart +++ b/lib/views/video_view/video_player.dart @@ -277,7 +277,7 @@ class VideoPlayerPageState extends ConsumerState { } }).catchError((error) { // Handle specific error from 'downloadVideo' - if (error.toString() == 'Exception: Not connected to Wi-Fi') { + if (error.toString() == "Not connected to Wi-Fi. Download cancelled.") { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Please connect to Wi-Fi to download videos')), ); From 0f1b95c2f8e0988915389a0ffc3d660b00701d64 Mon Sep 17 00:00:00 2001 From: ge59dil Date: Wed, 24 Jan 2024 21:49:19 +0100 Subject: [PATCH 3/8] download func --- lib/view_models/download_view_model.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index 3c4f0d08..f88bc3fe 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -44,7 +44,7 @@ class DownloadViewModel extends StateNotifier { // Check if 'Download Over Wi-Fi Only' is enabled and if not connected to Wi-Fi - if (downloadOverWifiOnly == (await isConnectedToWifi())) { + if (downloadOverWifiOnly == !(await isConnectedToWifi())) { _logger.w('Not connected to Wi-Fi. Download cancelled.'); throw Exception('Not connected to Wi-Fi'); } From cd55ec4bfe3ac839bd4a8b22989b172a2b2c779e Mon Sep 17 00:00:00 2001 From: ge59dil Date: Thu, 25 Jan 2024 09:41:13 +0100 Subject: [PATCH 4/8] added error handing --- lib/view_models/download_view_model.dart | 4 +- lib/views/video_view/video_player.dart | 61 ++++++++++++++++++------ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index f88bc3fe..0f763177 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -41,10 +41,8 @@ class DownloadViewModel extends StateNotifier { String videoUrl, Int64 streamId, String fileName,{required bool downloadOverWifiOnly,}) async { try { _logger.d('Download Over Wi-Fi Only setting is: $downloadOverWifiOnly'); - - // Check if 'Download Over Wi-Fi Only' is enabled and if not connected to Wi-Fi - if (downloadOverWifiOnly == !(await isConnectedToWifi())) { + if (downloadOverWifiOnly && !(await isConnectedToWifi())) { _logger.w('Not connected to Wi-Fi. Download cancelled.'); throw Exception('Not connected to Wi-Fi'); } diff --git a/lib/views/video_view/video_player.dart b/lib/views/video_view/video_player.dart index 651145ba..34780777 100644 --- a/lib/views/video_view/video_player.dart +++ b/lib/views/video_view/video_player.dart @@ -44,8 +44,8 @@ class VideoPlayerPageState extends ConsumerState { onDownload: () => _downloadVideo(widget.stream), ), Expanded( - child: - ChatView(isActive: _isChatVisible, streamID: widget.stream.id),), + child: + ChatView(isActive: _isChatVisible, streamID: widget.stream.id),), ], ); } @@ -62,7 +62,9 @@ class VideoPlayerPageState extends ConsumerState { await ref .read(courseViewModelProvider.notifier) .getCourseWithID(widget.stream.courseID); - Course? course = ref.read(courseViewModelProvider).course; + Course? course = ref + .read(courseViewModelProvider) + .course; if (course != null) { if ((course.chatEnabled || course.vodChatEnabled) && widget.stream.chatEnabled) { @@ -90,7 +92,9 @@ class VideoPlayerPageState extends ConsumerState { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.stream.name)), - body: ref.read(videoViewModelProvider).isLoading + body: ref + .read(videoViewModelProvider) + .isLoading ? const Center(child: CircularProgressIndicator()) : _buildVideoLayout(), ); @@ -132,10 +136,12 @@ class VideoPlayerPageState extends ConsumerState { // Seek to the last progress. Future _seekToLastProgress() async { Progress progress = - ref.read(videoViewModelProvider).progress ?? Progress(progress: 0.0); + ref + .read(videoViewModelProvider) + .progress ?? Progress(progress: 0.0); final position = Duration( seconds: (progress.progress * - _controllerManager.videoPlayerController.value.duration.inSeconds) + _controllerManager.videoPlayerController.value.duration.inSeconds) .round(), ); await _controllerManager.videoPlayerController.seekTo(position); @@ -200,7 +206,9 @@ class VideoPlayerPageState extends ConsumerState { } void _switchPlaylist(String newPlaylistUrl) async { - if (ref.read(videoViewModelProvider).videoSource == newPlaylistUrl) { + if (ref + .read(videoViewModelProvider) + .videoSource == newPlaylistUrl) { Logger().i("Already displaying $newPlaylistUrl"); return; } @@ -235,8 +243,11 @@ class VideoPlayerPageState extends ConsumerState { _isChatVisible = !_isChatVisible; }); } + void _downloadVideo(Stream stream) { - final isDownloadWithWifiOnly = ref.watch(settingViewModelProvider).isDownloadWithWifiOnly; + final isDownloadWithWifiOnly = ref + .watch(settingViewModelProvider) + .isDownloadWithWifiOnly; // Extract the "Combined" download URL from the Stream object String? combinedDownloadUrl; @@ -261,32 +272,52 @@ class VideoPlayerPageState extends ConsumerState { const SnackBar(content: Text('Starting download...')), ); + // Call the download function from the DownloadViewModel // Call the download function from the DownloadViewModel ref .read(downloadViewModelProvider.notifier) - .downloadVideo(combinedDownloadUrl, stream.id, fileName, downloadOverWifiOnly: isDownloadWithWifiOnly) + .downloadVideo(combinedDownloadUrl, stream.id, fileName, + downloadOverWifiOnly: isDownloadWithWifiOnly,) .then((localPath) { if (localPath.isNotEmpty) { + // Download successful ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Video Downloaded')), ); } else { + // Download failed, but not due to Wi-Fi (since it would throw an exception) ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Download failed')), ); } }).catchError((error) { - // Handle specific error from 'downloadVideo' - if (error.toString() == "Not connected to Wi-Fi. Download cancelled.") { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Please connect to Wi-Fi to download videos')), + // _logger.d('Caught error: ${error.toString()}'); + if (error.toString().contains("Not connected to Wi-Fi")) { + // Show a dialog for Wi-Fi error + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text("Download Failed"), + content: const Text( + "You are not connected to Wi-Fi. Please connect to Wi-Fi to download the video.",), + actions: [ + TextButton( + child: const Text("OK"), + onPressed: () { + Navigator.of(context).pop(); // Dismiss the dialog + }, + ), + ], + ); + }, ); } else { + // For other errors, show a snackbar ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error: ${error.toString()}')), ); } }); } - -} +} \ No newline at end of file From 45b0f6fc4c4148eabea9f3e8aa73b2ae1164104f Mon Sep 17 00:00:00 2001 From: ge59dil Date: Fri, 26 Jan 2024 09:31:31 +0100 Subject: [PATCH 5/8] rollbacking Info.plist --- ios/Runner/Info.plist | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 5616f190..fdc5768a 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -2,10 +2,6 @@ -NSLocationWhenInUseUsageDescription -This app needs location access to determine your Wi-Fi network -NSLocationAlwaysUsageDescription -This app needs location access to determine your Wi-Fi network CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion From ef7fd74b8497780db81470447ddf1e79f81cef58 Mon Sep 17 00:00:00 2001 From: ge59dil Date: Fri, 26 Jan 2024 21:21:17 +0100 Subject: [PATCH 6/8] Added changes for mobile data. --- lib/models/settings/setting_state_model.dart | 2 +- lib/view_models/download_view_model.dart | 18 +-- lib/views/video_view/video_player.dart | 149 +++++++++++++------ 3 files changed, 107 insertions(+), 62 deletions(-) diff --git a/lib/models/settings/setting_state_model.dart b/lib/models/settings/setting_state_model.dart index 729fb2a3..0e1b34c0 100644 --- a/lib/models/settings/setting_state_model.dart +++ b/lib/models/settings/setting_state_model.dart @@ -21,7 +21,7 @@ class SettingState { this.isLightMode =false, this.isSystemDefault =true, this.isPushNotificationsEnabled = true, - this.isDownloadWithWifiOnly = true, + this.isDownloadWithWifiOnly = false, }); SettingState copyWith({ diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index 953f3505..0cfbeab3 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:fixnum/fixnum.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/models/download/download_state_model.dart'; @@ -28,24 +27,11 @@ class DownloadViewModel extends StateNotifier { } } - Future isConnectedToWifi() async { - var connectivityResult = await (Connectivity().checkConnectivity()); - if (connectivityResult == ConnectivityResult.wifi) { - return true; - } else { - return false; - } - } + Future downloadVideo( - String videoUrl, Int64 streamId, String fileName,{required bool downloadOverWifiOnly,}) async { + String videoUrl, Int64 streamId, String fileName,) async { try { - _logger.d('Download Over Wi-Fi Only setting is: $downloadOverWifiOnly'); - // Check if 'Download Over Wi-Fi Only' is enabled and if not connected to Wi-Fi - if (downloadOverWifiOnly && !(await isConnectedToWifi())) { - _logger.w('Not connected to Wi-Fi. Download cancelled.'); - throw Exception('Not connected to Wi-Fi'); - } final directory = await getApplicationDocumentsDirectory(); final filePath = '${directory.path}/$fileName'; Dio dio = Dio(); diff --git a/lib/views/video_view/video_player.dart b/lib/views/video_view/video_player.dart index 0b2b2f4b..0de000db 100644 --- a/lib/views/video_view/video_player.dart +++ b/lib/views/video_view/video_player.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; @@ -31,6 +32,7 @@ class VideoPlayerPageState extends ConsumerState { bool _isChatVisible = false; bool _isChatActive = false; + Widget _buildVideoLayout() { return Column( children: [ @@ -41,11 +43,11 @@ class VideoPlayerPageState extends ConsumerState { currentStream: widget.stream, isChatVisible: _isChatVisible, isChatActive: _isChatActive, - onDownload: (type) => _downloadVideo(widget.stream,type), + onDownload: (type) => _downloadVideo(widget.stream, type), ), Expanded( - child: - ChatView(isActive: _isChatVisible, streamID: widget.stream.id),), + child: + ChatView(isActive: _isChatVisible, streamID: widget.stream.id),), ], ); } @@ -62,7 +64,9 @@ class VideoPlayerPageState extends ConsumerState { await ref .read(courseViewModelProvider.notifier) .getCourseWithID(widget.stream.courseID); - Course? course = ref.read(courseViewModelProvider).course; + Course? course = ref + .read(courseViewModelProvider) + .course; if (course != null) { if ((course.chatEnabled || course.vodChatEnabled) && widget.stream.chatEnabled) { @@ -90,7 +94,9 @@ class VideoPlayerPageState extends ConsumerState { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text(widget.stream.name)), - body: ref.read(videoViewModelProvider).isLoading + body: ref + .read(videoViewModelProvider) + .isLoading ? const Center(child: CircularProgressIndicator()) : _buildVideoLayout(), ); @@ -132,10 +138,12 @@ class VideoPlayerPageState extends ConsumerState { // Seek to the last progress. Future _seekToLastProgress() async { Progress progress = - ref.read(videoViewModelProvider).progress ?? Progress(progress: 0.0); + ref + .read(videoViewModelProvider) + .progress ?? Progress(progress: 0.0); final position = Duration( seconds: (progress.progress * - _controllerManager.videoPlayerController.value.duration.inSeconds) + _controllerManager.videoPlayerController.value.duration.inSeconds) .round(), ); await _controllerManager.videoPlayerController.seekTo(position); @@ -200,7 +208,9 @@ class VideoPlayerPageState extends ConsumerState { } void _switchPlaylist(String newPlaylistUrl) async { - if (ref.read(videoViewModelProvider).videoSource == newPlaylistUrl) { + if (ref + .read(videoViewModelProvider) + .videoSource == newPlaylistUrl) { Logger().i("Already displaying $newPlaylistUrl"); return; } @@ -236,30 +246,32 @@ class VideoPlayerPageState extends ConsumerState { }); } - void _downloadVideo(Stream stream,String type) { - final isDownloadWithWifiOnly = ref - .watch(settingViewModelProvider) - .isDownloadWithWifiOnly; + Future _downloadVideo(Stream stream, String type) async { + // Extract the "Combined" download URL from the Stream object + bool canDownload = await _handleDownloadConnectivity(stream, type); + if (!canDownload) return; // Exit if download should not proceed - // Extract the "Combined" download URL from the Stream object String? downloadUrl; for (var download in stream.downloads) { if (download.friendlyName == type) { - downloadUrl = download.downloadURL; + downloadUrl = download.downloadURL; break; } } //combinedDownloadUrl="https://file-examples.com/storage/fe5048eb7365a64ba96daa9/2017/04/file_example_MP4_480_1_5MG.mp4"; // Check if the Combined URL is found if (downloadUrl == null) { + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Download type "$type" not available for this lecture')), + SnackBar(content: Text( + 'Download type "$type" not available for this lecture',),), ); return; } // Use the extracted URL for downloading String fileName = "stream.mp4"; + if (!mounted) return; ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Starting download...')), ); @@ -267,8 +279,7 @@ class VideoPlayerPageState extends ConsumerState { ref .read(downloadViewModelProvider.notifier) - .downloadVideo(downloadUrl, stream.id, fileName, - downloadOverWifiOnly: isDownloadWithWifiOnly,) + .downloadVideo(downloadUrl, stream.id, fileName,) .then((localPath) { if (localPath.isNotEmpty) { // Download successful @@ -281,37 +292,85 @@ class VideoPlayerPageState extends ConsumerState { const SnackBar(content: Text('Download failed')), ); } - }).catchError((error) { - // _logger.d('Caught error: ${error.toString()}'); - if (error.toString().contains("Not connected to Wi-Fi")) { - // Show a dialog for Wi-Fi error - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text("Download Failed"), - content: const Text( - "You are not connected to Wi-Fi. Please connect to Wi-Fi to download the video.",), - actions: [ - TextButton( - child: const Text("OK"), - onPressed: () { - Navigator.of(context).pop(); // Dismiss the dialog - }, - ), - ], - ); - }, - ); - } else { - // For other errors, show a snackbar - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text('Error: ${error.toString()}')), - ); - } }); } + + Future _showDownloadConfirmationDialog() async { + return await showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext dialogContext) { + return AlertDialog( + title: const Text("Download Video"), + content: const Text( + "You are on mobile data. Would you like to download the video over mobile data?",), + actions: [ + TextButton( + child: const Text("No"), + onPressed: () { + Navigator.of(dialogContext).pop(false); + }, + ), + TextButton( + child: const Text("Yes"), + onPressed: () { + Navigator.of(dialogContext).pop(true); + }, + ), + ], + ); + }, + ) ?? false; // If dialog is dismissed, return false } + void _showMobileDataNotAllowedDialog() { + showDialog( + context: context, + barrierDismissible: false, // User must tap a button for the dialog to close + builder: (BuildContext dialogContext) { + return AlertDialog( + title: const Text("Download Not Allowed"), + content: const Text( + "You are currently on mobile data. Video cannot be downloaded over mobile data due to your settings.",), + actions: [ + TextButton( + child: const Text("OK"), + onPressed: () { + Navigator.of(dialogContext).pop(); // Dismiss dialog + }, + ), + ], + ); + }, + ); + } + + Future _handleDownloadConnectivity(Stream stream, String type) async { + final isDownloadWithWifiOnly = ref + .watch(settingViewModelProvider) + .isDownloadWithWifiOnly; + + var connectivityResult = await (Connectivity().checkConnectivity()); + + // If 'Download Over Wi-Fi Only' is enabled and connected to mobile, show a dialog + if (connectivityResult == ConnectivityResult.mobile && isDownloadWithWifiOnly) { + if (!mounted) return false; + _showMobileDataNotAllowedDialog(); + return false; + } + // If on mobile data and 'Download Over Wi-Fi Only' is disabled, ask for confirmation + if (connectivityResult == ConnectivityResult.mobile && !isDownloadWithWifiOnly) { + bool shouldProceed = await _showDownloadConfirmationDialog(); + if (!mounted) return false; + if (!shouldProceed) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Download cancelled')), + ); + return false; + } + } + return true; // Proceed with download if all checks pass + } +} From cc14c79c9ae4a9013549a829d2ae55a99f455bfb Mon Sep 17 00:00:00 2001 From: ge59dil Date: Sat, 27 Jan 2024 23:10:24 +0100 Subject: [PATCH 7/8] solved delete bug --- lib/view_models/download_view_model.dart | 30 ++++++++++++++---------- lib/views/video_view/video_player.dart | 2 +- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index 0cfbeab3..7370ba59 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -64,32 +64,35 @@ class DownloadViewModel extends StateNotifier { _logger.e('Error fetching downloaded videos: $e'); } } - Future deleteDownload(int videoId) async { _logger.i('Deleting downloaded video with ID: $videoId'); + _logger.d('Current state before deletion: ${state.downloadedVideos}'); try { String? filePath = state.downloadedVideos[videoId]; + _logger.d('File path to delete: $filePath'); + if (filePath != null && filePath.isNotEmpty) { final file = File(filePath); if (await file.exists()) { await file.delete(); _logger.d('Deleted video file at: $filePath'); - - final prefs = await SharedPreferences.getInstance(); - final updatedDownloads = - Map.from(state.downloadedVideos); - updatedDownloads.remove(videoId); - - // Save updated list to SharedPreferences - await prefs.setString( - 'downloadedVideos', - json.encode(updatedDownloads - .map((key, value) => MapEntry(key.toString(), value)),),); - state = state.copyWith(downloadedVideos: updatedDownloads); } else { _logger.w('File not found: $filePath'); } + + // Update the state and SharedPreferences after deletion + final updatedDownloads = Map.from(state.downloadedVideos); + updatedDownloads.remove(videoId); + + final prefs = await SharedPreferences.getInstance(); + await prefs.setString( + 'downloadedVideos', + json.encode(updatedDownloads.map((key, value) => MapEntry(key.toString(), value))), + ); + + state = state.copyWith(downloadedVideos: updatedDownloads); + _logger.d('Updated state after deletion: ${state.downloadedVideos}'); } else { _logger.w('No file path found for video ID: $videoId'); } @@ -98,6 +101,7 @@ class DownloadViewModel extends StateNotifier { } } + Future deleteAllDownloads() async { _logger.i('Deleting all downloaded videos'); diff --git a/lib/views/video_view/video_player.dart b/lib/views/video_view/video_player.dart index 0de000db..27cca8f2 100644 --- a/lib/views/video_view/video_player.dart +++ b/lib/views/video_view/video_player.dart @@ -258,7 +258,7 @@ class VideoPlayerPageState extends ConsumerState { break; } } - //combinedDownloadUrl="https://file-examples.com/storage/fe5048eb7365a64ba96daa9/2017/04/file_example_MP4_480_1_5MG.mp4"; + //downloadUrl="https://file-examples.com/storage/fed61549c865b2b5c9768b5/2017/04/file_example_MP4_480_1_5MG.mp4"; // Check if the Combined URL is found if (downloadUrl == null) { if (!mounted) return; From e6948b0bc5cab781cc8db14d86015447657dd28e Mon Sep 17 00:00:00 2001 From: ge59dil Date: Sun, 28 Jan 2024 00:02:03 +0100 Subject: [PATCH 8/8] solved error --- lib/view_models/download_view_model.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index 7370ba59..c8e103ba 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'package:fixnum/fixnum.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/models/download/download_state_model.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -30,7 +29,7 @@ class DownloadViewModel extends StateNotifier { Future downloadVideo( - String videoUrl, Int64 streamId, String fileName,) async { + String videoUrl, int streamId, String fileName,) async { try { final directory = await getApplicationDocumentsDirectory(); final filePath = '${directory.path}/$fileName'; @@ -127,7 +126,7 @@ class DownloadViewModel extends StateNotifier { } } - bool isStreamDownloaded(Int64 id) { + bool isStreamDownloaded(int id) { final int streamIdInt = id.toInt(); // Convert Int64 to int return state.downloadedVideos.containsKey(streamIdInt); }