How to Display Download Progress in Alert Dialog box using Dio package - flutter

I am Currently trying to download a file from URL using Dio Package. I can successfully download the file but I want to display the progress in an Alert Dialog and once Download is Successful Then it Should Display "Download Successful". I tried but couldn't find any solution
Packages I used are : Dio, Path_Provider and permission_handler.
my Code :
class WatchView extends StatefulWidget {
#override
_WatchViewState createState() => _WatchViewState();
}
class _WatchViewState extends State<WatchView> {
final Dio dio = Dio();
bool loading = false;
double progress = 0;
Future<bool> saveVideo(String url, String fileName) async {
Directory directory;
try {
if (Platform.isAndroid) {
if (await _requestPermission(Permission.storage)) {
String newPath =
"storage/emulated/0/Android/data/com.appname.test./files/";
print(directory);
newPath = newPath + "folder";
directory = Directory(newPath);
} else {
return false;
}
} else {
if (await _requestPermission(Permission.photos)) {
directory = await getTemporaryDirectory();
} else {
return false;
}
}
File saveFile = File(directory.path + "/$fileName");
if (!await directory.exists()) {
await directory.create(recursive: true);
}
if (await directory.exists()) {
await dio.download(url, saveFile.path,
onReceiveProgress: (value1, value2) {
setState(() {
progress = value1 / value2;
});
});
return true;
}
return false;
} catch (e) {
print(e);
return false;
}
}
Future<bool> _requestPermission(Permission permission) async {
if (await permission.isGranted) {
return true;
} else {
var result = await permission.request();
if (result == PermissionStatus.granted) {
return true;
}
}
return false;
}
downloadFile(String file1) async {
setState(() {
loading = true;
progress = 0;
});
bool downloaded = await saveVideo(file1, "test.file_extention");
if (downloaded) {
print("File Downloaded");
} else {
print("Problem Downloading File");
}
setState(() {
loading = false;
});
}
#override
Widget build(BuildContext context) {
var provider = Provider.of<ProviderModel>(context);
return Scaffold(
appBar: AppBar(
elevation: 0.0,
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
),
body: SingleChildScrollView(
physics: ClampingScrollPhysics(),
child: Container(
),
floatingActionButton: FloatingActionButton.extended(
label: Text(
'Download',
),
backgroundColor: Colors.indigo[700],
icon: Icon(Icons.download_rounded),
onPressed: () {
downloadFile(
"Download URL,
);
},
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
);
},
);
}
}

Related

Agora Video calling local view doesn't start, warning: invalid local view

I am developing a voice/video-calling app using Flutter and Agora rtc engine (v 5.3.1). I have followed all the necessary steps for generating token and joining a channel. But, I can't see the local camera view in the UI and the logs gives me warning saying: "onWarning warn 8 msg invalid view for local video". Any leads would be big help, thanks in advance.
Logs:
W/spdlog (30579): [2023-01-04 21:02:33.375] [0] [warning] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:43 onWarning warn 8 msg invalid view for local video
W/spdlog (30579): [2023-01-04 21:02:33.375] [0] [warning] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:43 onWarning warn 16
msg nullptr
I/spdlog (30579): [2023-01-04 21:02:33.375] [0] [info] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:72 onJoinChannelSuccess
channel b8667da0-8c6a-11ed-a9fb-578e8ad35bd6 uid 1
W/spdlog (30579): [2023-01-04 21:02:33.377] [0] [warning] /tmp/jenkins/IRIS-SDK/rtc/cxx/src/internal/rtc_engine_event_handler.cc:43 onWarning warn 16
msg nullptr
Call Screen Widget:
imports...
String baseUrl = 'https://...';
class CallScreen extends ConsumerStatefulWidget {
final Call call;
const CallScreen({Key? key, required this.call, }) : super(key: key);
#override
_CallScreenState createState() => _CallScreenState();
}
class _CallScreenState extends ConsumerState<CallScreen> {
int uid = 1;
List<int> _remoteUids = [];
bool isJoined = false,
switchCamera = true,
openMicrophone = true,
enableSpeakerphone = false;
late bool openCamera;
late RtcEngine _engine;
#override
void initState() {
initAgora();
openCamera = widget.call.isVideoCall;
super.initState();
}
Future<String?> _getToken() async {
String url = baseUrl + "/rtc/" + widget.call.callId + "/publisher/uid/" + uid.toString() + "/";;
String? token;
try{
var resp = await http.get(Uri.parse(url));
if(resp.statusCode == 200){
token = jsonDecode(resp.body)['rtcToken'];
return token;
}
else{
showMySnackBar(context: context, content: "Token Status ERR: "+jsonDecode(resp.body)['message']);
return null;
}
}
catch(e){
showMySnackBar(context: context, content: "Token Err: "+e.toString());
return null;
}
}
void _joinChannel() async {
String? token = await _getToken();
if(token != null){
await _engine.joinChannel(token, widget.call.callId, null, uid);
}
else{
showMySnackBar(context: context, content: 'Token is null!');
}
}
void _leaveChannel() async {
ref.read(callControllerProvider).endCall(
widget.call.callerId,
widget.call.receiverId,
context,
widget.call.isGroupChat
);
if(widget.call.isVideoCall) await _engine.stopPreview();
await _engine.leaveChannel();
}
void _switchCamera() {
_engine.switchCamera()
.then((value) {
setState(() {
switchCamera = !switchCamera;
});
})
.catchError((err) {
//print('switchCamera $err');
});
}
void _switchMicrophone() async {
// await _engine.muteLocalAudioStream(!openMicrophone);
await _engine.enableLocalAudio(!openMicrophone)
.then((value) {
setState(() {
openMicrophone = !openMicrophone;
});
})
.catchError((err) {
// print('enableLocalAudio $err');
});
}
void _switchSpeakerphone() {
_engine.setEnableSpeakerphone(!enableSpeakerphone)
.then((value) {
setState(() {
enableSpeakerphone = !enableSpeakerphone;
});
})
.catchError((err) {
//print('setEnableSpeakerphone $err');
});
}
void initAgora() async {
try{
await [Permission.microphone, Permission.camera].request();
_engine = await RtcEngine.createWithContext(RtcEngineContext(AgoraConfig.appId));
_engine.setEventHandler(
RtcEngineEventHandler(
warning: (warn) {
showMySnackBar(context: context, content: "Warn: "+warn.name);
},
error: (err) {
showMySnackBar(context: context, content: 'OnErr event: '+err.name);
},
joinChannelSuccess: (String channel, int userId, int elapsed) {
// print("local user ${connection.localUid} joined");
if(mounted){
setState(() {
isJoined = true;
uid = userId;
});
}
showMySnackBar(context: context, content: 'You ($userId) have joined the call!');
},
userJoined: (int remoteUid, int elapsed) {
//debugPrint("remote user $remoteUid joined");
if(mounted){
setState(() {
_remoteUids.add(remoteUid);
});
}
},
userOffline: (int remoteUid, UserOfflineReason reason) {
//debugPrint("remote user $remoteUid left channel");
if(mounted){
setState(() {
_remoteUids.removeWhere((element) => element == remoteUid);
});
}
},
leaveChannel: (stats) {
if(mounted){
setState(() {
isJoined = false;
if(!widget.call.isGroupChat || _remoteUids.length == 1){
_remoteUids.clear();
}
});
}
},
// onTokenPrivilegeWillExpire: (RtcConnection connection, String token) {
// debugPrint('[onTokenPrivilegeWillExpire] connection: ${connection.toJson()}, token: $token');
// },
),
);
await _engine.setChannelProfile(ChannelProfile.LiveBroadcasting);
//await _engine.setClientRole(ClientRole.Broadcaster);
await _engine.enableVideo();
if(widget.call.isVideoCall){
await _engine.startPreview();
}
else{
await _engine.muteLocalVideoStream(true);
await _engine.muteAllRemoteVideoStreams(true);
}
_joinChannel();
}
catch(e){
showMySnackBar(context: context, content: "Init Err: "+e.toString());
}
}
#override
void dispose() {
_leaveChannel();
_engine.destroy();
super.dispose();
}
// Display remote user's video
Widget _remoteVideo() {
if (_remoteUids.isNotEmpty) {
//TODO check for video on or off or if video call:
return rtc_remote_view.SurfaceView(
uid: _remoteUids[0],
channelId: widget.call.callId,
);
}
else {
return const Text(
'Please wait for others to join',
textAlign: TextAlign.center,
);
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async { _leaveChannel(); return true; },
child: Scaffold(
backgroundColor: Colors.white,
body: Stack(
children: [
Center(
child: _remoteVideo(),
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(right: 18.0, bottom: 12),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: ColoredBox(
color: Colors.grey.shade200,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 125, maxHeight: 175),
child: AspectRatio(
aspectRatio: 9/16,
child: Center(
child: isJoined
?
( //TODO: check for video on or off or if video call:
openCamera
? rtc_local_view.SurfaceView(
channelId: widget.call.callId,
)
: const Icon(
Icons.videocam_off_rounded,
color: Colors.black,
size: appActionsIconsSize,
)
)
: const CircularProgressIndicator(),
),
),
),
),
),
),
),
],
),
),
);
}
}
I found the issue: I was not setting the ClientRoleType correctly and that caused error in finding local view. One needs to define ClientRoleType (based on your logic) and ChannelProfileType.broadcast and everything seems to work.

Flutter visibility is not changing in Stack widget

String fullPath;
bool isLoading = false;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
bottomNavigationBar: _bottomTab(),
appBar: AppBar(
title: Text('View'),),
body: Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: Visibility(
visible: isLoading, child: CircularProgressIndicator()),
),
Align(
alignment: Alignment.center,
child: Container(
color: Colors.white,
height: MediaQuery.of(context).size.height / 1.5,
child: WebviewScaffold(
url: weburl,
displayZoomControls: true,
withJavascript: true,
scrollBar: true,
withZoom: true,
hidden: true,
),
),
),
],
),
);
}
void _onItemTapped(int index) {
setState(() {
switch (index) {
case 0:
break;
case 1:
_makingPhoneCall();
break;
case 2:
setState(() {
isLoading = true;
getPermission('download');
});
break;
case 3:
setState(() {
isLoading = true;
getPermission('share');
});
break;
}
});
}
void getPermission(String downOrShare) async {
try {
print("getPermission");
Map<Permission, PermissionStatus> permissions =
await [Permission.storage].request();
print(permissions[Permission.storage]);
String path = await ExtStorage.getExternalStoragePublicDirectory(
ExtStorage.DIRECTORY_DOWNLOADS);
fullPath = "$path/" + type + ".pdf";
download2(dio, pdfUrl, fullPath, downOrShare);
} catch (e) {
print(e);
}
}
void shareFile(File file) async {
try {
setState(() {
isLoading = false;
});
if (!await file.exists()) {
await file.create(recursive: true);
file.writeAsStringSync("test for share documents file");
}
ShareExtend.share(file.path, "file");
} catch (e) {
print(e);
}
}
Future download2(
Dio dio, String url, String savePath, String downOrShare) async {
try {
//get pdf from link
Response response = await dio.get(
url,
onReceiveProgress: showDownloadProgress,
//Received data with List<int>
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
validateStatus: (status) {
return status < 500;
}),
);
//write in download folder
File file = File(savePath);
var raf = file.openSync(mode: FileMode.write);
raf.writeFromSync(response.data);
await raf.close();
if (downOrShare == 'share') {
shareFile(file);
} else if (downOrShare == 'print') {
// printPdf(file);
} else {
isLoading = false;
Fluttertoast.showToast(
msg: type + "Downloaded in " + fullPath,
toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.white,
textColor: Colors.black,
fontSize: 16.0);
}
} catch (e) {
print(e);
}
}
I am using webview and bottom navigation bar in my application. I have download, share option in bottom navigation. Whenever I click the download and share option I want to show CircularProgressIndicator(). Also I have given setState({}) to make visible true or false. Why is it not working?
Move your indicator widget to bottom of webview widget

How to download attachment in Flutter using enough_mail

I need to download the attachment from the mime message object. Bellow, I have added my class file. Which came with the mime message. Need help to extract the attachments and download them.
class EmailScreen extends StatefulWidget {
EmailScreen({
Key key,
this.mimeMessage,
this.userInfo
}) : super(key: key);
final MimeMessage mimeMessage;
final UserInfo userInfo;
#override
EmailScreenState createState() => EmailScreenState(
mimeMessage: mimeMessage,
userInfo: userInfo
);
}
class EmailScreenState extends State<EmailScreen> {
MimeMessage mimeMessage;
UserInfo userInfo;
EmailScreenState({Key key,this.mimeMessage,this.userInfo});
#override
Widget build(BuildContext context) {
throw UnimplementedError();
}
}
Here is the below code that I have used to download attachments using enough_mail 1.3.6.
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: mimeMessage.findContentInfo().length,
itemBuilder: (context, index) {
ContentInfo contentInfo = mimeMessage
.findContentInfo()[index];
return Container(
padding: EdgeInsets.only(left: 10.0),
margin: EdgeInsets.only(right: 5.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10)
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
child: Text(
contentInfo.fileName,
overflow: TextOverflow.ellipsis,
)
),
IconButton(
onPressed: (){
setState(() {
MimePart mimePart = mimeMessage.getPart(contentInfo.fetchId);
Uint8List uint8List = mimePart.decodeContentBinary();
MySnackBar.show(
context,
MySnackBar.loadingIcon,
"Downloading....!"
);
saveFile(context,uint8List,contentInfo.fileName).then((value){
MySnackBar.hide(context);
if(value){
MySnackBar.show(
context,
MySnackBar.successIcon,
"Completed!"
);
}else{
MySnackBar.show(
context,
MySnackBar.errorIcon,
"Something went wrong!"
);
}
}).catchError((err){
MySnackBar.hide(context);
MySnackBar.show(
context,
MySnackBar.errorIcon,
"Something went wrong!"
);
});
});
},
icon: Icon(
Icons.download,
color: Colors.grey,
)
)
],
),
);
}
)
Future<bool> saveFile(BuildContext context,Uint8List uint8List, String fileName) async {
Directory directory;
try {
if (Platform.isAndroid) {
if (await requestPermission(Permission.storage)) {
directory = await getExternalStorageDirectory();
String newPath = "";
print(directory);
List<String> paths = directory.path.split("/");
for (int x = 1; x < paths.length; x++) {
String folder = paths[x];
if (folder != "Android") {
newPath += "/" + folder;
} else {
break;
}
}
newPath = newPath + "/NetxMail";
directory = Directory(newPath);
} else {
return false;
}
} else {
if (await requestPermission(Permission.photos)) {
directory = await getTemporaryDirectory();
} else {
return false;
}
}
if (!await directory.exists()) {
await directory.create(recursive: true);
}
if (await directory.exists()) {
File file = new File('${directory.path}/$fileName');
print("file path = ${file.path}");
await file.writeAsBytes(uint8List);
return true;
}
return false;
} catch (e) {
print(e);
return false;
}
}
Future<bool> requestPermission(Permission permission) async {
if (await permission.isGranted) {
return true;
} else {
var result = await permission.request();
if (result == PermissionStatus.granted) {
return true;
}
}
return false;
}

Error opening PDF file after downloading from server Flutter

Hello I have a screen in the app that downloads a PDF file and displays the download progress in percent. After downloading, the file is opened using the package of pdf_render: ^ 1.0.10. Sometimes it opens and displays the PDF file and sometimes it does not open the file and I have a blank screen. I have no fault in the console and I do not know what the fault is. Thank you
Flutter App :
class Web_view_vehicle extends StatefulWidget {
var choice ;
var name_vehicle;
Web_view_vehicle({ required this.choice , this.name_vehicle}) : super();
#override
_Web_view_vehicleState createState() => _Web_view_vehicleState();
}
class _Web_view_vehicleState extends State<Web_view_vehicle> {
bool downloading = false;
String progressString = "";
String path = '';
late List data ;
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/teste.pdf');
}
Future<File> writeCounter(Uint8List stream) async {
final file = await _localFile;
// Write the file
return file.writeAsBytes(stream);
}
Future<Uint8List> fetchPost() async {
Dio dio = Dio();
var response = await dio.get(widget.choice,
onReceiveProgress: (rec, total) {
print("Rec: $rec , Total: $total");
if(!mounted)return;
setState(() {
downloading = true;
progressString = ((rec / total) * 100).toStringAsFixed(0) + "%";
});
},options: Options(responseType: ResponseType.bytes));
final responseJson = response.data;
if (!mounted) {
}
setState(() {
downloading = false;
progressString = "Completed";
});
print("Download completed");
return responseJson;
}
loadPdf() async {
writeCounter((await fetchPost()));
path = (await _localFile).path;
if (!mounted) return;
setState(() {});
}
#override
void initState() {
super.initState();
loadPdf();
}
#override
Widget build(BuildContext context) {
Color? bgColor = Colors.grey[300];
return Scaffold(
backgroundColor: bgColor,
appBar: AppBar(
leading: Padding(
padding: const EdgeInsets.fromLTRB(5.0 , 0.0 , 0.0 , 0.0),
child: new IconButton(
icon: new Icon(Icons.arrow_back),
onPressed: (){Navigator.pop(context,true);}
),
),
title: Text('מדריך לרכב ${widget.name_vehicle}',textAlign: TextAlign.center,textDirection: TextDirection.rtl,),
backgroundColor: Colors.red[400],
centerTitle: true,
actions: <Widget>[
],
),
body:
(path.length > 5)?
PdfViewer.openFile(path,
):
Center(child: Column(crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,mainAxisSize: MainAxisSize.max,
children: [
CircularProgressIndicator(),
Text('טוען מדריך ${progressString}',textDirection: TextDirection.rtl,textAlign: TextAlign.center,)
],
))
);
}
}

How to send dynamic url from DataProvider to PDF Flutter

I'm new to Flutter. I have DataProvider which consists of Pdf data like it's Title, pdfURL and etc and I created a ListView on that ListView I have some items.
Whenever I click on any item it should open specified pdf url on PDF VIEWER. I want to pass that data dynamically to the getFileFromUrl; how should I pass that data.
This is my DataProvider class:
class DataProvider with ChangeNotifier{
List<PdfBook> _pdfItems = [
PdfBook(
id: 'p1',
title: 'PDF Bookmark Sample',
pdfUrl: 'https://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf',
avatar: 'T',
),
PdfBook(
id: 'p2',
title: 'PDF 995',
pdfUrl: 'http://www.pdf995.com/samples/pdf.pdf',
avatar: 'T2',
),
];
List<PdfBook> get pdfItems{
return [..._pdfItems];
}
PdfBook findById(String id){
return _pdfItems.firstWhere((item) => item.id == id);
}
}
This is my PdfViewState:
class PdfItem extends StatefulWidget {
#override
_PdfItemState createState() => _PdfItemState();
}
class _PdfItemState extends State<PdfItem> {
String assetPDFPath = "";
String urlPDFPath = "";
#override
void initState() {
super.initState();
getFileFromAsset("assets/mypdf.pdf").then((f) {
setState(() {
assetPDFPath = f.path;
print(assetPDFPath);
});
});
getFileFromUrl("http://www.pdf995.com/samples/pdf.pdf").then((f) {
setState(() {
urlPDFPath = f.path;
print(urlPDFPath);
});
});
}
Future<File> getFileFromAsset(String asset) async {
try {
var data = await rootBundle.load(asset);
var bytes = data.buffer.asUint8List();
var dir = await getApplicationDocumentsDirectory();
File file = File("${dir.path}/mypdf.pdf");
File assetFile = await file.writeAsBytes(bytes);
return assetFile;
} catch (e) {
throw Exception("Error opening asset file");
}
}
Future<File> getFileFromUrl(String url) async {
try {
var data = await http.get(url);
var bytes = data.bodyBytes;
var dir = await getApplicationDocumentsDirectory();
File file = File("${dir.path}/mypdfonline.pdf");
File urlFile = await file.writeAsBytes(bytes);
return urlFile;
} catch (e) {
throw Exception("Error opening url file");
}
}
#override
Widget build(BuildContext context) {
final pdf = Provider.of<PdfBook>(context, listen: false);
return ListTile(
title: Text(pdf.title),
onTap: () {
if (urlPDFPath != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
PdfViewPage(path: urlPDFPath)));
}
},
leading: CircleAvatar(
child: Text(pdf.avatar),
backgroundColor: Theme.of(context).accentColor,
),
trailing: Icon(Icons.arrow_right),
);
}
}
This is my ListView Class:
class PdfListView extends StatelessWidget {
#override
Widget build(BuildContext context) {
final pdfData = Provider.of<DataProvider>(context);
final pdf = pdfData.pdfItems;
return Scaffold(
appBar: AppBar(
title: Text("PDF Books"),
),
body: ListView.builder(
itemCount: pdf.length,
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
value: pdf[i],
child: PdfItem(),
),
),
);
}
}