Flutter visibility is not changing in Stack widget - flutter

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

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.

Pass user data to profile screen from firebase

I am tring to pas data to user profile screen from firebase
i have got error Unhandled Exception: 'package:cloud_firestore/src/collection_reference.dart': Failed assertion: line 116 pos 14: 'path.isNotEmpty': a document path must be a non-empty string
what do i need fix?
user prfile controller
lass ProfileController extends GetxController {
final Rx<Map<String, dynamic>> _user = Rx<Map<String, dynamic>>({});
Map<String, dynamic> get user => _user.value;
Rx<String> _uid = ''.obs;
updateUserID(String uid) {
_uid.value = uid;
getUserData();
}
void getUserData() async {
print("HELLO");
List<String> thumbnails = [];
// var myVideos = await firestore
// .collection('videos')
// .where('uid', isEqualTo: "9GFyxV41rkd0Iu0oy1tctobVNk92")
// .get();
//
// for (int i = 0; i < myVideos.docs.length; i++) {
// thumbnails.add((myVideos.docs[i].data() as dynamic)['thumbnail']);
// }
DocumentSnapshot userDoc =
await firestore.collection('users').doc(_uid.value).get();
final userData = userDoc.data()! as dynamic;
print(userData);
String name = userData['name'];
String profilePhoto = userData['profilePhoto'];
int likes = 0;
int followers = 0;
int following = 0;
bool isFollowing = false;
// for (var item in myVideos.docs) {
// likes += (item.data()['likes'] as List).length;
// }
// var followerDoc = await firestore
// .collection('users')
// .doc(_uid.value)
// .collection('followers')
// .get();
// var followingDoc = await firestore
// .collection('users')
// .doc(_uid.value)
// .collection('following')
// .get();
// followers = followerDoc.docs.length;
// following = followingDoc.docs.length;
// firestore
// .collection('users')
// .doc(_uid.value)
// .collection('followers')
// .doc(authController.user.uid)
// .get()
// .then(
// (value) {
// if (value.exists) {
// isFollowing = true;
// } else {
// isFollowing = false;
// }
// },
// );
_user.value = {
'followers': followers.toString(),
'following': following.toString(),
'isFollowing': isFollowing,
'likes': likes.toString(),
'profilePhoto': profilePhoto,
'name': name,
'thumbnails': thumbnails,
};
update();
}
followUser() async {
var doc = await firestore
.collection('users')
.doc(_uid.value)
.collection('followers')
.doc(authController.user.uid)
.get();
if (!doc.exists) {
await firestore
.collection('users')
.doc(_uid.value)
.collection('followers')
.doc(authController.user.uid)
.set({});
await firestore
.collection('users')
.doc(authController.user.uid)
.collection('following')
.doc(_uid.value)
.set({});
_user.value
.update('followers', (value) => (int.parse(value) + 1).toString());
} else {
await firestore
.collection('users')
.doc(_uid.value)
.collection('followers')
.doc(authController.user.uid)
.delete();
await firestore
.collection('users')
.doc(authController.user.uid)
.collection('following')
.doc(_uid.value)
.delete();
_user.value
.update('followers', (value) => (int.parse(value) - 1).toString());
}
_user.value.update('isFollowing', (value) => !value);
update();
}
}
auth Controller
class AuthController extends GetxController {
static AuthController instance = Get.find(); //TODO 2
var displayName = '';
var displayPhoto = '';
String myId = '';
late Rx<User?> _user; //TODO 1
User get user => _user.value!; //TODO 3
Rx<File?>? pickedImageVal;
File? get profilePhoto => pickedImageVal!.value;
FirebaseAuth auth = FirebaseAuth.instance;
User? get userProfile => auth.currentUser;
var isSignedIn = false.obs;
var _googleSignIn = GoogleSignIn();
var googleAccount = Rx<GoogleSignInAccount?>(null);
var firebaseStorage = FirebaseStorage.instance;
var firestore = FirebaseFirestore.instance;
// var authController = AuthController.instance;
#override
void onReady() {
super.onReady();
_user = Rx<User?>(firebaseAuth.currentUser);
_user.bindStream(firebaseAuth.authStateChanges());
ever(_user, _setInitialScreen);
}
_setInitialScreen(User? user) {
if (user == null) {
Get.offAll(OnboardingPage());
} else {
Get.offAll(const Home());
}
}
#override
void onInit() {
displayName = userProfile != null ? userProfile!.displayName! : '';
super.onInit();
}
void pickImage() async {
final pickedImage =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedImage != null) {
Get.snackbar(
'プロファイル写真', 'You have successfully selected your profile picture!');
}
pickedImageVal = Rx<File?>(File(pickedImage!.path));
}
Future<String> _uploadToStorage(File image) async {
Reference ref =
firebaseStorage.ref().child('profilePics').child(auth.currentUser!.uid);
UploadTask uploadTask = ref.putFile(image);
TaskSnapshot snap = await uploadTask;
String downloadUrl = await snap.ref.getDownloadURL();
return downloadUrl;
}
void signUp(String name, String email, String password, File? image) async {
try {
await auth
.createUserWithEmailAndPassword(email: email, password: password)
.then((value) {
displayName = name;
auth.currentUser!.updateDisplayName(name);
});
isSignedIn = true.obs;
String downloadUrl = await _uploadToStorage(profilePhoto!);
model.UserM user = model.UserM(
name: name,
email: email,
uid: auth.currentUser!.uid,
profilePhoto: downloadUrl,
);
await firestore
.collection('users')
.doc(auth.currentUser!.uid)
.set(user.toJson());
update();
Get.offAll(() => Root());
} on FirebaseAuthException catch (e) {
String title = e.code.replaceAll(RegExp('-'), ' ').capitalize!;
String message = '';
if (e.code == 'weak-password') {
message = 'The password provided is too weak.';
} else if (e.code == 'email-already-in-use') {
message = ('The account already exists for that email.');
} else {
message = e.message.toString();
}
Get.snackbar(title, message,
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white);
} catch (e) {
Get.snackbar('Error occured!', e.toString(),
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white);
}
}
void signIn(String email, String password) async {
try {
await auth
.signInWithEmailAndPassword(email: email, password: password)
.then((value) => displayName = userProfile!.displayName!);
isSignedIn = true.obs;
myId = userProfile!.uid; //TODO 4
update();
Get.offAll(() => Root());
} on FirebaseAuthException catch (e) {
String title = e.code.replaceAll(RegExp('-'), ' ').capitalize!;
String message = '';
if (e.code == 'wrong-password') {
message = 'Invalid Password. Please try again!';
} else if (e.code == 'user-not-found') {
message =
('The account does not exists for $email. Create your account by signing up.');
} else {
message = e.message.toString();
}
Get.snackbar('ユーザー名が存在しません。', 'アカウントを作成してください。',
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white);
} catch (e) {
//TODO; what is Get.snackbar.e.tostring(), means?
Get.snackbar(
'Error occured!',
e.toString(),
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white,
);
}
}
void resetPassword(String email) async {
try {
await auth.sendPasswordResetEmail(email: email);
Get.back();
} on FirebaseAuthException catch (e) {
String title = e.code.replaceAll(RegExp('-'), ' ').capitalize!;
String message = '';
if (e.code == 'user-not-found') {
message =
('The account does not exists for $email. Create your account by signing up.');
} else {
message = e.message.toString();
}
Get.snackbar(title, message,
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white);
} catch (e) {
Get.snackbar('Error occured!', e.toString(),
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white);
}
}
void signInWithGoogle() async {
try {
googleAccount.value = await _googleSignIn.signIn();
print(googleAccount.value);
displayName = googleAccount.value!.displayName!;
displayPhoto = googleAccount.value!.photoUrl!;
isSignedIn.value = true;
update(); // <-- without this the isSignedin value is not updated.
} catch (e) {
Get.snackbar('Error occured!', e.toString(),
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white);
}
}
void signout() async {
try {
await auth.signOut();
await _googleSignIn.signOut();
displayName = '';
isSignedIn.value = false;
update();
Get.offAll(() => Root());
} catch (e) {
Get.snackbar('Error occured!', e.toString(),
snackPosition: SnackPosition.BOTTOM,
backgroundColor: kPrimaryColor,
colorText: Colors.white);
}
}
}
//
// extension StringExtention on String{
// String capitalizedString(){
// return'${this[0].toUpperCase()}${this.substring(1)}';
// }
// }
user profile screen
class ProfileScreen extends StatefulWidget {
final String uid;
ProfileScreen({Key? key, required this.uid}) : super(key: key);
#override
State<ProfileScreen> createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen> {
final ProfileController profileController = Get.put(ProfileController());
#override
void initState() {
super.initState();
profileController.updateUserID(widget.uid);
}
#override
Widget build(BuildContext context) {
return GetBuilder<ProfileController>(
init: ProfileController(),
builder: (controller) {
// if (controller.user.isEmpty) {
// return Center(
// child: CircularProgressIndicator(),
// );
// }
print(controller.user);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.black12,
leading: Icon(Icons.person_add_alt_1_outlined),
actions: [
Icon(Icons.more_horiz),
],
title: Text(controller.user['name'].toString()),
),
body: SafeArea(
child: SingleChildScrollView(
child: Column(
children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ClipOval(
child: CachedNetworkImage(
fit: BoxFit.cover,
imageUrl: controller.user['profilePhoto']
.toString(),
height: 100,
width: 100,
placeholder: (context, url) =>
CircularProgressIndicator(),
errorWidget: (context, url, error) =>
Icon(Icons.error)),
)
],
),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
Text(controller.user['following'].toString()),
SizedBox(
height: 5,
),
Text('following'),
],
),
Container(
color: Colors.black54,
width: 1,
height: 15,
margin: EdgeInsets.symmetric(horizontal: 15),
),
Column(
children: [
Text(controller.user['followers'].toString()),
SizedBox(
height: 5,
),
Text('follower'),
],
),
Container(
color: Colors.black54,
width: 1,
height: 15,
margin: EdgeInsets.symmetric(horizontal: 15),
),
Column(
children: [
Text(controller.user['likes'].toString()),
SizedBox(
height: 5,
),
Text('likes'),
],
)
],
),
SizedBox(
height: 15,
),
Container(
width: 140,
height: 47,
decoration: BoxDecoration(
border: Border.all(
color: Colors.black12,
),
),
child: Center(
child: InkWell(
onTap: () {
// if (widget.uid == authController.user.uid) {
// authController.signOut();
// } else {
// controller.followUser();
},
// },
child: const Text(
"",
// widget.uid == authController.user.uid
// ? 'sign out'
// controller.user['isFollowing']
// ? 'unfollow'
// : 'follow',
),
),
),
),

Why flutter pdf setPage is not working if set the value return from AlertDialog in android only?

My code is view the pdf using by flutter_pdfview from online url. Opening the pdf is no issue. So I wrote the pagination at floatingActionButton. There is "Previous", "Page / Total Page" and "Next". If click page button, Alert Dialog box pop up and user can enter the page and can go to specified page. It is working on iOS. But at Android, after enter the page number on Dialog and click "Move" button and then dialog return the entered value and set the page number at
await snapshot.data!.setPage(pageNumber - 1);
But it is not call the PDFView's onPageChanged. If I don't call the dialog and just simply call snapshot.data!.setPage(pageNumber - 1), it is working.
I think something wrong with dialog.
May I know why it is only happening on android and only happening if set the page number return from dialog?
First Pdf page
Dialog to enter page number
Full source code
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:thitsarparami/helper/enum.dart';
import 'package:thitsarparami/widgets/circular_progress_indicator_widget.dart';
class PdfView extends StatefulWidget {
final String url;
final LoadPDF loadPDF;
final String title;
const PdfView(
{Key? key, required this.title, required this.url, required this.loadPDF})
: super(key: key);
#override
State<PdfView> createState() => _PdfViewerState();
}
class _PdfViewerState extends State<PdfView> with WidgetsBindingObserver {
String? path;
bool _isLoading = true;
TextEditingController? textController;
final Completer<PDFViewController> _controller =
Completer<PDFViewController>();
int? pages = 0;
int? currentPage = 0;
bool isReady = false;
String errorMessage = '';
bool isButtonActive = false;
loadDocument() async {
String fileName = widget.url.split("/").last;
switch (widget.loadPDF) {
case LoadPDF.assets:
fromAsset(widget.url, fileName).then((f) {
setState(() {
path = f.path;
_isLoading = false;
});
});
break;
case LoadPDF.url:
createFileOfPdfUrl().then((f) {
setState(() {
path = f.path;
_isLoading = false;
});
});
break;
case LoadPDF.file:
File file = File(widget.url);
setState(() {
path = file.path;
_isLoading = false;
});
break;
}
}
Future<File> createFileOfPdfUrl() async {
Completer<File> completer = Completer();
//print("Start download file from internet!");
try {
final url = widget.url;
final filename = url.substring(url.lastIndexOf("/") + 1);
var request = await HttpClient().getUrl(Uri.parse(url));
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
var dir = await getApplicationDocumentsDirectory();
//print("Download files");
//print("${dir.path}/$filename");
File file = File("${dir.path}/$filename");
await file.writeAsBytes(bytes, flush: true);
completer.complete(file);
} catch (e) {
throw Exception('Error parsing asset file!');
}
return completer.future;
}
Future<File> fromAsset(String asset, String filename) async {
// To open from assets, you can copy them to the app storage folder, and the access them "locally"
Completer<File> completer = Completer();
try {
var dir = await getApplicationDocumentsDirectory();
File file = File("${dir.path}/$filename");
var data = await rootBundle.load(asset);
var bytes = data.buffer.asUint8List();
await file.writeAsBytes(bytes, flush: true);
completer.complete(file);
} catch (e) {
throw Exception('Error parsing asset file!');
}
return completer.future;
}
#override
void initState() {
super.initState();
loadDocument();
textController = TextEditingController();
}
#override
void dispose() {
textController?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
centerTitle: true,
backgroundColor: Theme.of(context).backgroundColor,
elevation: 0,
title: AutoSizeText(
widget.title,
style: Theme.of(context).appBarTheme.titleTextStyle,
),
leading: IconButton(
onPressed: () {
Navigator.pop(context);
},
icon: Icon(
Icons.arrow_back,
color: Theme.of(context).primaryIconTheme.color!,
),
),
),
body: Center(
child: _isLoading
? const CircularProgressIndicatorWidget()
: PDFView(
filePath: path,
enableSwipe: true,
swipeHorizontal: false,
autoSpacing: false,
pageFling: true,
pageSnap: true,
defaultPage: currentPage!,
fitPolicy: FitPolicy.BOTH,
preventLinkNavigation:
false, // if set to true the link is handled in flutter
onRender: (_pages) {
setState(() {
pages = _pages;
isReady = true;
});
},
onError: (error) {
setState(() {
errorMessage = error.toString();
});
//print(error.toString());
},
onPageError: (page, error) {
setState(() {
errorMessage = '$page: ${error.toString()}';
});
//print('$page: ${error.toString()}');
},
onViewCreated: (PDFViewController pdfViewController) {
_controller.complete(pdfViewController);
},
onLinkHandler: (String? uri) {
//print('goto uri: $uri');
},
onPageChanged: (int? page, int? total) {
//print('page change: $page/$total');
setState(
() {
currentPage = page;
},
);
},
),
),
floatingActionButton: FutureBuilder<PDFViewController>(
future: _controller.future,
builder: (context, AsyncSnapshot<PDFViewController> snapshot) {
if (snapshot.hasData) {
return FloatingActionButton.extended(
label: Row(
children: [
IconButton(
icon: Icon(Icons.navigate_before,
color: (currentPage! > 0) ? Colors.white : Colors.grey),
onPressed: (currentPage! < pages!)
? () async {
await snapshot.data!.setPage(currentPage! - 1);
}
: null,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0,
side: const BorderSide(
color: Colors.white,
),
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
onPressed: () async {
final result = await openDialog();
if (result == null || result.isEmpty) return;
int pageNumber = int.parse(result);
await snapshot.data!.setPage(pageNumber - 1);
},
child: Text("${currentPage! + 1}"),
),
Text(" / $pages"),
IconButton(
icon: Icon(Icons.navigate_next,
color: (currentPage! + 1 < pages!)
? Colors.white
: Colors.grey),
onPressed: (currentPage! < pages!)
? () async {
await snapshot.data!.setPage(currentPage! + 1);
}
: null,
),
],
),
onPressed: null,
);
}
return Container();
},
),
);
}
Future<String?> openDialog() => showDialog<String>(
context: context,
builder: (context) => StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: const Text('Go to page'),
content: TextField(
autofocus: true,
decoration: const InputDecoration(hintText: 'Page number'),
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
controller: textController,
onChanged: (value) {
if (value.isNotEmpty) {
int pageNumber = int.parse(value);
setState(() {
isButtonActive = pageNumber < pages!;
});
}
},
onSubmitted: (_) => gotToPage(),
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
textController?.clear();
},
child: const Text('Cancel'),
),
TextButton(
style: TextButton.styleFrom(
onSurface: Theme.of(context).primaryColor),
onPressed: isButtonActive
? () {
gotToPage();
textController?.clear();
}
: null,
child: const Text('Move'),
),
],
);
},
),
);
void gotToPage() {
Navigator.of(context).pop(textController?.text);
}
}
I am not sure why this error occurred in android. It is happening because opening the keyboard. So Now I am using number picker and it is working now.

How to make progress indicator (downloading percentage) in Global Snackbar?

i am trying to implement a global downloadFile() function and a global snackbar, so that the snackbar and the downloading keep working even after navigating to another widget.
the problem is the downloading progress (the downloading percentage) doesn't update at all.
this is CustomSnackBar
class CustomSnackBar {
static bool isDownloading = false;
static String progress = "0%";
CustomSnackBar._();
static Future<void> downloadFile(
BuildContext context, String fileUrl, fileName) async {
Dio dio = Dio();
isDownloading = true;
try {
var dir = await getApplicationDocumentsDirectory();
await dio
.download(fileUrl, "${dir.path}/notifications_files/$fileName.pdf",
onReceiveProgress: (rec, total) {
progress = '${((rec / total) * 100).toStringAsFixed(0)} %';
buildErrorSnackbar(context, "empty");
});
isDownloading = false;
} catch (e) {
print(e);
}
}
static buildErrorSnackbar(BuildContext context, String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
duration: const Duration(days: 100),
backgroundColor: kPrimaryColor,
content: snacBarDownloading(progress),
action: SnackBarAction(
textColor: kWhiteColor,
label: 'Dismiss',
onPressed: () {},
),
),
);
}
}
Widget snacBarDownloading(String progress) {
// print(progress);
return Row(children: [
const SizedBox(
width: 25,
height: 25,
child: CircularProgressIndicator(color: kWhiteColor)),
const SizedBox(
width: 10,
),
Text("Downloading $progress ...",
style: const TextStyle(color: kWhiteColor))
]);
}
and this where i call the downloading function
return InkWell(
onLongPress: () {
if (!isDownloading &&
widget.notificationList[index].fileUrl != null &&
widget.notificationList[index].fileUrl!.isNotEmpty) {
CustomSnackBar.downloadFile(
context,
widget.notificationList[index].fileUrl!,
widget.notificationList[index].serviceId!);
}
},

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

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,
);
},
);
}
}