How to show downloading status of file in percentage in flutter by using dio plugin? - flutter

How to use dio plugin for file downloading ? also, if file is already downloaded then user can directly view it without download. if it is not then user can download and also see progress indicator with downloaded percentage.
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'dart:ui';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:external_path/external_path.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:get/get.dart';
import 'package:nb_utils/nb_utils.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:world_virtual_coin/services/app_utils.dart';
import 'package:world_virtual_coin/services/theme.dart';
import 'package:world_virtual_coin/widget/colors.dart';
import '../services/size_config.dart';
class DownloadCtrl {
String progressString = "0";
late String localPath;
ReceivePort _port = ReceivePort();
StreamController<int> indexController = StreamController<int>.broadcast();
String downloadTaskId = '';
DownloadCtrl();
init() {
IsolateNameServer.registerPortWithName(
_port.sendPort,
'invoice_send_port',
);
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
if (status == DownloadTaskStatus.complete) {
Future.delayed(const Duration(seconds: 1), () {
Get.back();
// indexController.add(100);
// downloadTaskId = id;
FlutterDownloader.open(taskId: id);
});
}
progressString = progress.toString();
});
FlutterDownloader.registerCallback(downloadCallback);
}
Future _findLocalPath() async {
var directory;
if (Platform.isAndroid) {
// directory = await getExternalStorageDirectory();
directory = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOWNLOADS);
} else {
directory = await getApplicationDocumentsDirectory();
}
return directory is String ? directory : directory.path;
}
Future download(String url, BuildContext context) async {
var androidVersion;
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
var deviceData = <String, dynamic>{};
try {
if (Platform.isAndroid) {
AndroidDeviceInfo deviceInfo = await deviceInfoPlugin.androidInfo;
androidVersion = num.parse(deviceInfo.version.release.toString());
// androidVersion = 9;
// print("Device version" + androidVersion.toString());
}
} on PlatformException {
deviceData = <String, dynamic>{'Error:': 'Failed to get platform version.'};
}
_checkPermission().then((hasGranted) async {
if (hasGranted) {
localPath = await _findLocalPath();
final savedDir = Directory(localPath);
bool hasExisted = await savedDir.exists();
if (!hasExisted) {
savedDir.create();
}
String pathOfFile = '$localPath/${url.split('/').last}';
File file = File(pathOfFile);
if (await file.exists() && Platform.isAndroid) {
_performVersionSpecificOperation(file, androidVersion, url, localPath, context);
} else {
_proceedDownload(url, localPath, context);
}
}
});
}
Future showLoadingBottomSheet(context, path) async {
showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
isDismissible: false,
builder: (BuildContext context) {
return WillPopScope(
onWillPop: () {
return Future.value();
},
child: Container(
color: Colors.black87.withOpacity(0.7),
width: w(100),
height: h(20),
child: Stack(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
StreamBuilder(
stream: indexController.stream,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return (snapshot.hasData && snapshot.data! < 100)
? Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(colorPrimary),
),
5.height,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
text('Downloading ', textColor: colorPrimary, fontFamily: fontBold, fontSize: 17.0),
10.width,
text(
snapshot.hasData ? '${snapshot.data} %' : '',
textColor: colorPrimary,
fontFamily: fontBold,
fontSize: 17.0,
),
],
),
],
)
: SizedBox.shrink();
},
),
5.height,
StreamBuilder(
stream: indexController.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return (snapshot.hasData && snapshot.data == 100)
? Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
flex: 27,
child: text(
'File saved at:',
textColor: colorPrimary,
fontSize: 16.0,
),
),
Expanded(
flex: 73,
child: text(
'$path',
textColor: whiteColor,
fontFamily: fontMedium,
fontSize: 17.0,
),
),
],
),
),
5.height,
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: colorPrimary.withOpacity(0.15),
width: 2.5,
),
),
child: text(
'Open',
textColor: whiteColor,
fontFamily: fontBold,
).paddingSymmetric(
vertical: 2,
horizontal: 10,
),
).onTap(() {
Future.delayed(Duration(seconds: 1), () {
Get.back();
FlutterDownloader.open(taskId: downloadTaskId);
});
}),
],
)
: SizedBox.shrink();
},
)
],
),
const Align(
alignment: Alignment.topRight,
child: Icon(
Icons.cancel_presentation,
color: Colors.red,
size: 25,
),
).onTap(() {
Get.back();
}),
],
),
),
);
},
);
}
Future<bool> _checkPermission() async {
PermissionStatus status = await Permission.storage.status;
// Either the permission was already granted before or the user just granted it.
if (status.isGranted) {
return true;
} else {
bool permission = await Permission.storage.request().isGranted;
if (permission) {
return true;
} else {
return false;
}
}
}
static void downloadCallback(
String id,
DownloadTaskStatus status,
int progress,
) {
final SendPort? send = IsolateNameServer.lookupPortByName('invoice_send_port');
send!.send([id, status, progress]);
}
void dispose() {
IsolateNameServer.removePortNameMapping('invoice_send_port');
indexController.close();
}
_proceedDownload(url, path, context) async {
showLoadingBottomSheet(context, path);
await FlutterDownloader.enqueue(
url: url,
savedDir: localPath,
showNotification: true,
openFileFromNotification: true,
saveInPublicStorage: true,
);
}
_performVersionSpecificOperation(File file, androidVersion, url, path, context) async {
if (androidVersion <= 9) {
try {
await file.delete();
} catch (e) {
return 0;
}
_proceedDownload(url, path, context);
}
// else if (androidVersion == 10) {
// AppUtils.showErrorSnackBar('You have already downloaded this File');
// }
else {
_proceedDownload(url, path, context);
}
}
}
I made above class for download pdf. and below button has mathod to download it.
CustomButton(
onPressed: () {
DownloadCtrl().download("https://www.clickdimensions.com/links/TestPDFfile.pdf", context);
},
label: 'Save Pdf',
),
Now the problem is, initially pdf will download on click of button butif user tap second time it should check first file is already exist in device or not. if it is exist direct open it else proceed for download.
for that, I haved below plugins,
flutter_downloader: ^1.10.1+2
permission_handler: ^10.2.0
device_info_plus:
external_path: ^1.0.3

Related

Flutter: Bad state Error: cannot get a field on a DocumentSnapshotPlatform which does not exist

I'm new to Flutter and getting this issue.
Trying to develop a social media app which includes a chat feature. However, it says DocumentSnapshot is not exist.
Of course I understood that one thing is missing, it is clear. But I couldn't understand what is that missing thing and how to solve it.
I examined a lot of posts about this but I couldn't solve my issue. There is no misspelling between Cloud Firestore and my code. I couldn't understand am I missing key or something like this?
It looks like this
Sometimes it also can not upload the profile picture of person.
Here are my codes,
Thanks for helping.
I got this error when I try to type a message:
class Conversation extends StatefulWidget {
final String userId;
final String chatId;
const Conversation({required this.userId, required this.chatId});
#override
_ConversationState createState() => _ConversationState();
}
class _ConversationState extends State<Conversation> {
FocusNode focusNode = FocusNode();
ScrollController scrollController = ScrollController();
TextEditingController messageController = TextEditingController();
bool isFirst = false;
String? chatId;
#override
void initState() {
super.initState();
scrollController.addListener(() {
focusNode.unfocus();
});
print(widget.chatId);
if (widget.chatId == 'newChat') {
isFirst = true;
}
chatId = widget.chatId;
messageController.addListener(() {
if (focusNode.hasFocus && messageController.text.isNotEmpty) {
setTyping(true);
} else if (!focusNode.hasFocus ||
(focusNode.hasFocus && messageController.text.isEmpty)) {
setTyping(false);
}
});
}
setTyping(typing) {
//here
UserViewModel viewModel =
Provider.of<UserViewModel>(context, listen: false);
viewModel.setUser();
//here
var user = Provider.of<UserViewModel>(context, listen: false).user;
Provider.of<ConversationViewModel>(context, listen: false)
.setUserTyping(widget.chatId, user, typing);
}
#override
Widget build(BuildContext context) {
UserViewModel viewModel =
Provider.of<UserViewModel>(context, listen: false);
viewModel.setUser();
var user = Provider.of<UserViewModel>(context, listen: true).user;
return Consumer<ConversationViewModel>(
builder: (BuildContext context, viewModel, Widget? child) {
return Scaffold(
key: viewModel.scaffoldKey,
appBar: AppBar(
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.keyboard_backspace,
),
),
elevation: 0.0,
titleSpacing: 0,
title: buildUserName(),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: messageListStream(widget.chatId),
builder: (context, snapshot) {
if (snapshot.hasData) {
//snapshot.hasData
//print(snapshot.data);
print(viewModel);
List messages = snapshot.data!.docs;
viewModel.setReadCount(
widget.chatId, user, messages.length);
return ListView.builder(
controller: scrollController,
padding: EdgeInsets.symmetric(horizontal: 10.0),
itemCount: messages.length,
reverse: true,
itemBuilder: (BuildContext context, int index) {
Message message = Message.fromJson(
messages.reversed.toList()[index].data(),
);
print(message.content);
print(message.senderUid);
print(message.time);
print(message.type);
return ChatBubble(
message: '${message.content}',
time: message.time!,
isMe: message.senderUid == user!.uid,
type: message.type!,
);
},
);
} else {
return Center(child: circularProgress(context));
}
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 10.0,
child: Container(
constraints: BoxConstraints(maxHeight: 100.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
IconButton(
icon: Icon(
CupertinoIcons.photo_on_rectangle,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () => showPhotoOptions(viewModel, user),
),
Flexible(
child: TextField(
controller: messageController,
focusNode: focusNode,
style: TextStyle(
fontSize: 15.0,
color:
Theme.of(context).textTheme.headline6!.color,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
enabledBorder: InputBorder.none,
border: InputBorder.none,
hintText: "Type your message",
hintStyle: TextStyle(
color: Theme.of(context)
.textTheme
.headline6!
.color,
),
),
maxLines: null,
),
),
IconButton(
icon: Icon(
Ionicons.send,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
if (messageController.text.isNotEmpty) {
sendMessage(viewModel, user);
}
},
),
],
),
),
),
)
],
),
),
);
});
}
_buildOnlineText(
var user,
bool typing,
) {
if (user.isOnline) {
if (typing) {
return "typing...";
} else {
return "online";
}
} else {
return 'last seen ${timeago.format(user.lastSeen.toDate())}';
}
}
buildUserName() {
return StreamBuilder(
stream: usersRef.doc('${widget.userId}').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
DocumentSnapshot documentSnapshot =
snapshot.data as DocumentSnapshot<Object?>;
UserModel user = UserModel.fromJson(
documentSnapshot.data() as Map<String, dynamic>,
);
return InkWell(
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 10.0, right: 10.0),
child: Hero(
tag: user.email!,
child: CircleAvatar(
radius: 25.0,
backgroundImage: CachedNetworkImageProvider(
'${user.photoUrl}',
),
),
),
),
SizedBox(width: 10.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'${user.username}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
),
SizedBox(height: 5.0),
StreamBuilder(
stream: chatRef.doc('${widget.chatId}').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
DocumentSnapshot? snap =
snapshot.data as DocumentSnapshot<Object?>;
Map? data = snap.data() as Map<dynamic, dynamic>?;
Map? usersTyping = data?['typing'] ?? {};
return Text(
_buildOnlineText(
user,
usersTyping![widget.userId] ?? false,
),
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 11,
),
);
} else {
return SizedBox();
}
},
),
],
),
),
],
),
onTap: () {},
);
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}
showPhotoOptions(ConversationViewModel viewModel, var user) {
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text("Camera"),
onTap: () {
sendMessage(viewModel, user, imageType: 0, isImage: true);
},
),
ListTile(
title: Text("Gallery"),
onTap: () {
sendMessage(viewModel, user, imageType: 1, isImage: true);
},
),
],
);
},
);
}
sendMessage(ConversationViewModel viewModel, var user,
{bool isImage = false, int? imageType}) async {
String msg;
if (isImage) {
msg = await viewModel.pickImage(
source: imageType!,
context: context,
chatId: widget.chatId,
);
} else {
msg = messageController.text.trim();
messageController.clear();
}
Message message = Message(
content: '$msg',
senderUid: user?.uid,
type: isImage ? MessageType.IMAGE : MessageType.TEXT,
time: Timestamp.now(),
);
if (msg.isNotEmpty) {
if (isFirst) {
print("FIRST");
String id = await viewModel.sendFirstMessage(widget.userId, message);
setState(() {
isFirst = false;
chatId = id;
});
} else {
viewModel.sendMessage(
widget.chatId,
message,
);
}
}
}
Stream<QuerySnapshot> messageListStream(String documentId) {
return chatRef
.doc(documentId)
.collection('messages')
.orderBy('time')
.snapshots();
}
}
Also here is the ViewModel codes if I did something wrong here:
class ConversationViewModel extends ChangeNotifier {
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
ChatService chatService = ChatService();
bool uploadingImage = false;
final picker = ImagePicker();
File? image;
sendMessage(String chatId, Message message) {
chatService.sendMessage(
message,
chatId,
);
}
Future<String> sendFirstMessage(String recipient, Message message) async {
String newChatId = await chatService.sendFirstMessage(
message,
recipient,
);
return newChatId;
}
setReadCount(String chatId, var user, int count) {
chatService.setUserRead(chatId, user, count);
}
setUserTyping(String chatId, var user, bool typing) {
chatService.setUserTyping(chatId, user, typing);
}
pickImage({int? source, BuildContext? context, String? chatId}) async {
PickedFile? pickedFile = source == 0
? await picker.getImage(
source: ImageSource.camera,
)
: await picker.getImage(
source: ImageSource.gallery,
);
if (pickedFile != null) {
CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: pickedFile.path,
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
uiSettings: [
AndroidUiSettings(
toolbarTitle: 'Crop image',
toolbarColor: Theme.of(context!).appBarTheme.backgroundColor,
toolbarWidgetColor: Theme.of(context).iconTheme.color,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false,
),
IOSUiSettings(
minimumAspectRatio: 1.0,
),
],
);
Navigator.of(context).pop();
if (croppedFile != null) {
uploadingImage = true;
image = File(croppedFile.path);
notifyListeners();
showInSnackBar("Uploading image...", context);
String imageUrl = await chatService.uploadImage(image!, chatId!);
return imageUrl;
}
}
}
void showInSnackBar(String value, context) {
ScaffoldMessenger.of(context).removeCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(value),
),
);
}
}
Here is the ChatService code:
class ChatService {
FirebaseStorage storage = FirebaseStorage.instance;
sendMessage(Message message, String chatId) async {
//will send message to chats collection with the usersId
await chatRef.doc("$chatId").collection("messages").add(message.toJson());
//will update "lastTextTime" to the last time a text was sent
await chatRef.doc("$chatId").update({"lastTextTime": Timestamp.now()});
}
Future<String> sendFirstMessage(Message message, String recipient) async {
User user = firebaseAuth.currentUser!;
DocumentReference ref = await chatRef.add({
'users': [recipient, user.uid],
});
await sendMessage(message, ref.id);
return ref.id;
}
Future<String> uploadImage(File image, String chatId) async {
Reference storageReference =
storage.ref().child("chats").child(chatId).child(uuid.v4());
UploadTask uploadTask = storageReference.putFile(image);
await uploadTask.whenComplete(() => null);
String imageUrl = await storageReference.getDownloadURL();
return imageUrl;
}
//determine if a user has read a chat and updates how many messages are unread
setUserRead(String chatId, User user, int count) async {
DocumentSnapshot snap = await chatRef.doc(chatId).get();
Map reads = snap.get('reads') ?? {};
reads[user.uid] = count;
await chatRef.doc(chatId).update({'reads': reads});
}
//determine when a user has start typing a message
setUserTyping(String chatId, User user, bool userTyping) async {
DocumentSnapshot snap = await chatRef.doc(chatId).get();
Map typing = snap.get('typing');
typing[user.uid] = userTyping;
await chatRef.doc(chatId).update({
'typing': typing,
});
}
}

Flutter: SharedPreferences showing null value?

eg: details about the questions ............................................................................................i have set a address in home page using SharedPreferences but when i get that value in SearchModulePage showing null. i have tried many more times always showing null
Home Page:-
import 'dart:convert';
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:double_back_to_close_app/double_back_to_close_app.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geocoder/geocoder.dart';
import 'package:http/http.dart' as http;
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:newbharatbiz/Model%20Class/category_model.dart';
import 'package:newbharatbiz/Screens/SearchServiceProvider.dart';
import 'package:newbharatbiz/Screens/SubCategoryPage.dart';
import 'package:newbharatbiz/Utils/NavDrawer.dart';
import 'package:newbharatbiz/Utils/Serverlinks.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../Model Class/banner_model.dart';
import 'VendorRegistrationPage.dart';
import 'package:location/location.dart';
import 'package:flutter/services.dart';
var addressLine;
var getaddressLine;
var androidDeviceInfo;
var token;
var identifier;
var user_id;
var phone;
var name;
class HomePage extends StatefulWidget {
#override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State<HomePage> {
Future<BannerModel> BannerList() async {
final response = await http.get(Uri.parse(Serverlinks.all_banner));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
print(response);
return BannerModel.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
Future<CategoryModel> CategoryList() async {
final response = await http.get(Uri.parse(Serverlinks.category_list));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
print(response);
return CategoryModel.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
// late DateTime currentBackPressTime;
List<String> imagesList = [];
var currentLocation;
int currentIndexPage = 0;
#override
void initState() {
super.initState();
getUserLocation();
getdeviceid();
gettoken();
Setsharedpreferencevalue();
Getsharedpreferencevalue();
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.deepOrangeAccent,
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VendorRegistrationPage(),
),
);
},
),
drawer: NavDrawer(),
appBar:
AppBar(title: Text('New Bharat Biz'), centerTitle: true, actions: [
IconButton(
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchServiceProvider(),
),
);
},
icon: Icon(Icons.search),
),
]),
body: DoubleBackToCloseApp(
child: SingleChildScrollView(
child: Column(mainAxisAlignment: MainAxisAlignment.start, children: [
FutureBuilder<BannerModel>(
future: BannerList(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
print((snapshot.data));
snapshot.data!.banner.forEach((e) {
imagesList.add(snapshot.data!.imgPath + e.image);
print(imagesList.length);
});
return CarouselSlider(
//add return keyword here
options: CarouselOptions(
height: 160,
aspectRatio: 16 / 9,
viewportFraction: 0.8,
initialPage: 0,
enableInfiniteScroll: true,
reverse: false,
autoPlay: true,
autoPlayInterval: const Duration(seconds: 3),
autoPlayAnimationDuration:
const Duration(milliseconds: 800),
autoPlayCurve: Curves.fastOutSlowIn,
enlargeCenterPage: true,
),
items: imagesList
.map(
(item) => Center(
child: Image.network(item,
fit: BoxFit.cover, width: 1000)),
)
.toList(),
);
}
return const Center(
/*
child: SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
),
*/
);
}
// By default, show a loading spinner.
),
FutureBuilder<CategoryModel>(
future: CategoryList(),
builder: (BuildContext context, snapshot) {
//_getId();
if (snapshot.hasData) {
List<Result> data = snapshot.data!.result;
print((snapshot.data));
return GridView.builder(
itemCount: data.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
),
//padding: EdgeInsets.all(1),
itemBuilder: (ctx, index) {
return Padding(
padding: EdgeInsets.all(0.0),
child: new GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCategoryPage(
data[index].id,
),
),
);
},
child: new Container(
margin: const EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
decoration: BoxDecoration(
border: Border.all(
width: 0.5,
color: Colors.grey,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 25,
),
Image.network(
snapshot.data!.imgPath + data[index].coverPic,
height: 55,
width: 55,
),
SizedBox(
height: 10,
),
Expanded(
child: Text(
data[index].name,
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
textAlign: TextAlign.center,
),
)
],
),
),
),
);
},
);
} else {
return const Center(
child: SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
),
);
}
},
),
]),
),
snackBar: const SnackBar(
content: Text('Tap back again to leave'),
),
),
);
}
/*
Future<bool> onWillPop() {
DateTime now = DateTime.now();
if (currentBackPressTime == null ||
now.difference(currentBackPressTime) > Duration(seconds: 2)) {
currentBackPressTime = now;
return Future.value(false);
}
return Future.value(true);
}
*/
void getUserLocation() async {
//call this async method from whereever you need
LocationData? myLocation;
String error;
Location location = new Location();
try {
myLocation = await location.getLocation();
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_DENIED') {
error = 'please grant permission';
print(error);
}
if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {
error = 'permission denied- please enable it from app settings';
print(error);
}
myLocation = null;
}
currentLocation = myLocation;
final coordinates =
new Coordinates(myLocation?.latitude, myLocation?.longitude);
var addresses =
await Geocoder.local.findAddressesFromCoordinates(coordinates);
var first = addresses.first;
String adminArea = first.adminArea;
String locality = first.locality;
String subLocality = first.subLocality;
String subAdminArea = first.subAdminArea;
addressLine = first.addressLine;
String featureName = first.featureName;
String thoroughfare = first.thoroughfare;
String subThoroughfare = first.subThoroughfare;
/* print(' ${first.locality}, ${first.adminArea},${first.subLocality}, ${first.subAdminArea},${first.addressLine}, ${first.featureName},${first.thoroughfare}, ${first.subThoroughfare}');
return first;*/
}
gettoken() async {
//token = await FirebaseMessaging.instance.getToken();
FirebaseMessaging.instance.getToken().then((token) {
token = token.toString();
// do whatever you want with the token here
});
}
getdeviceid() async {
final DeviceInfoPlugin deviceInfoPlugin = new DeviceInfoPlugin();
if (Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
androidDeviceInfo = androidInfo.id!; //UUID for Android
} else if (Platform.isIOS) {
IosDeviceInfo iosInfo = await deviceInfoPlugin.iosInfo;
androidDeviceInfo = iosInfo.identifierForVendor; //UUID for Android
}
}
void Setsharedpreferencevalue() async {
setState(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('addressLine', addressLine);
prefs.setString('deviceID', androidDeviceInfo);
await prefs.setString("token", token!);
});
}
void Getsharedpreferencevalue() async {
setState(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
androidDeviceInfo = prefs.getString('deviceID');
getaddressLine = prefs.getString('addressLine');
token = prefs.getString('token');
user_id = prefs.getString('user_id');
phone = prefs.getString('phone');
name = prefs.getString('name');
print("info : ${androidDeviceInfo}");
});
}
}
SearchModulePage:-
import 'dart:convert';
import 'package:flutter_mapbox_autocomplete/flutter_mapbox_autocomplete.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:newbharatbiz/Screens/SubCategoryPage.dart';
import 'package:shared_preferences/shared_preferences.dart';
var addressLine;
TextEditingController Locality = TextEditingController();
class SearchModulePage extends StatefulWidget {
String id;
String catId;
String serviceName;
String image;
String imgPath;
SearchModulePage(
this.id, this.catId, this.serviceName, this.image, this.imgPath);
#override
_YourWidgetState createState() =>
_YourWidgetState(id, catId, serviceName, image, imgPath);
}
class _YourWidgetState extends State<SearchModulePage> {
String id;
String catId;
String serviceName;
String image;
String imgPath;
_YourWidgetState(
this.id, this.catId, this.serviceName, this.image, this.imgPath);
#override
void initState() {
super.initState();
getshareddprefernces();
}
#override
Widget build(BuildContext context) {
// getsharedprefernces();
return WillPopScope(
onWillPop: () async => true,
child: new Scaffold(
appBar: new AppBar(
title: new Text(serviceName),
leading: new IconButton(
icon: new Icon(Icons.arrow_back_outlined),
onPressed: () {
Navigator.pop(
context, true); // It worked for me instead of above line
/* Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => SubCategoryPage(
catId,
)),
);*/
}),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 30),
Image.network(
imgPath + image,
width: 60.0,
height: 60.0,
),
// Padding(padding: EdgeInsets.only(top: 15.0)),
const SizedBox(height: 20),
Text(serviceName,
style: TextStyle(color: Colors.black, fontSize: 15)),
// Padding(padding: EdgeInsets.only(top: 30.0)),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.all(20.0),
child: TextFormField(
controller: Locality,
readOnly: true,
// initialValue: addressLine,
// set it to a string by default
decoration: InputDecoration(
hintText: "Search your locality",
hintStyle: TextStyle(
color: Color(0xff323131),
),
suffixIcon: Icon(
Icons.location_on_rounded,
color: Color(0xFF00796B),
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MapBoxAutoCompleteWidget(
apiKey:
"pk.eyJ1IjoibmV3YmhhcmF0Yml6IiwiYSI6ImNrbWJqb3B5ZzIyZnUyd254M2JndmhnNnQifQ.Km7hMjBHD_kwHWL7x7Y-Jg",
hint: "Search your locality",
onSelect: (place) {
// TODO : Process the result gotten
Locality.text = place.placeName!;
},
limit: 10,
),
),
);
},
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// FocusScope.of(context).requestFocus(FocusNode());
addressLine = Locality.text;
if (addressLine == "") {
Fluttertoast.showToast(
msg: "Enter your locality",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.black54,
textColor: Colors.white,
fontSize: 16.0);
/* var snackBar = SnackBar(content: Text('Enter your locality'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);*/
} else {
// String locality = Locality.text;
}
},
child: Text("Submit"),
style: ElevatedButton.styleFrom(
primary: Color(0xFF00796B),
padding:
EdgeInsets.symmetric(horizontal: 100, vertical: 10),
textStyle:
TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
),
],
),
),
),
);
}
void getshareddprefernces() async {
setState(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
addressLine = await prefs.getString('addressLine');
Locality.text = addressLine.toString();
Fluttertoast.showToast(
msg: addressLine,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.black54,
textColor: Colors.white,
fontSize: 16.0);
});
}
}
You have to wait till all asynchronous process is over, then after that when all values (here address, deviceId and token) are set to variables, then you can save or set values to shared preferences.
Here is the sample code for you:
#override
void initState() {
super.initState();
initializeVariables().then((boolValue){
Setsharedpreferencevalue();
});
// ..
}
Future<Boolean> initializeVariables() async {
await getUserLocation();
await getdeviceid();
await gettoken();
return true;
}

I'd like to have https:// automatically attached to the link

When I tried to retrieve img from the website, the link started with /upload/.... instead of https://.
I want to have https:// written automatically in front of me. What should I do?
homepage:
<div class="photo_list">
<ul>
<li>
<a href="/yongwon-h/na/ntt/selectNttInfo.do?nttSn=85189591&mi=73747">
<img src="/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_85189591/thumb/thumb_img_9028b523-7bfb-466f-848c-65870a93b99c1616411595463.jpg" onerror="this.src='/images/co/na/noImg.gif'" alt="대표이미지">
<p>책을 가까이, 책은 나의 친구!! 아침독서의 생활화!!!</p>
<span>
2021.03.22
<br> 조회 6
</span>
</a>
</li>
</ul>
</div>
MY CODE:
import 'package:flutter/material.dart';
import 'package:flutter_share/flutter_share.dart';
import 'package:flutter_staggered_animations/flutter_staggered_animations.dart';
import 'package:http/http.dart' as http;
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as parser;
import 'package:url_launcher/url_launcher.dart';
class UpdatePost extends StatefulWidget {
#override
_UpdatePostState createState() => _UpdatePostState();
}
class _UpdatePostState extends State<UpdatePost> {
List<String> title = List();
List<String> post = List();
List<String> link = List();
List<String> image = List();
void _getDataFromWeb() async {
Uri uri = Uri.parse(
'http://yongwon-h.gne.go.kr/yongwon-h/na/ntt/selectNttList.do?mi=73747&&bbsId=62865');
final response = await http.get(uri);
dom.Document document = parser.parse(response.body);
final link2 = document.getElementsByClassName('photo_list');
final content = document.getElementsByClassName('photo_list');
final elements = document.getElementsByClassName('photo_list');
final ImageElement = document.getElementsByClassName('photo_list');
setState(() {
title = elements
.map((element) => element.getElementsByTagName("p")[0].innerHtml)
.toList();
post = content
.map((element) => element.getElementsByTagName("span")[0].innerHtml)
.toList();
link = link2
.map((element) =>
element.getElementsByTagName("a")[0].attributes['href'])
.toList();
image = ImageElement.map((element) =>
element.getElementsByTagName("img")[0].attributes['src']).toList();
});
}
Future<void> share(dynamic link, String title) async {
await FlutterShare.share(
title: 'Codding Application',
text: title,
linkUrl: link,
chooserTitle: 'Where You Want to Share');
}
#override
void initState() {
_getDataFromWeb();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black87,
body: post.length == 0
? Text("No data", style: TextStyle(color: Colors.white))
: ListView.builder(
itemCount: post.length,
itemBuilder: (context, index) {
return AnimationConfiguration.staggeredList(
position: index,
duration: const Duration(milliseconds: 375),
child: SlideAnimation(
child: FadeInAnimation(
child: GestureDetector(
onTap: () async {
dynamic url = link[index];
if (await canLaunch(url))
launch(url);
else {
print('error');
}
},
child: Padding(
padding: const EdgeInsets.all(10),
child: Card(
child: Container(
color: Colors.black87,
child: Column(
children: <Widget>[
Container(
child: Image.network(
image[index],
scale: 0.1,
),
),
Align(
alignment: Alignment.centerLeft,
child: Text(
title[index],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
fontSize: 20,
),
),
),
SizedBox(height: 15),
Text(
post[index],
style: TextStyle(
color: Colors.white,
),
),
Row(
children: <Widget>[
FlatButton(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5.0),
side: BorderSide(color: Colors.white)),
onPressed: () {
share(link[index], title[index]);
},
child: Text(
"Share With Friends",
style: TextStyle(
color: Colors.red,
),
),
),
SizedBox(width: 10),
FlatButton(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(5.0),
side: BorderSide(color: Colors.white)),
onPressed: () async {
dynamic url = link[index];
if (await canLaunch(url))
launch(url);
else {
print('error');
}
},
child: Text(
"Explore Post",
style: TextStyle(
color: Colors.red,
),
),
),
],
),
],
),
),
),
),
))),
);
},
),
);
}
}
conclusion:
I want to automatically put http://yongwon-h.gne.go.kr in front of the called tag a.
I feel like I'm asking repeatedly, but I really don't know. I googled thousands of sites in a week. Please help me.
import 'dart:async';
import 'package:wnetworking/wnetworking.dart';
final Map<String, Map<String, dynamic>> reDic = {
'notices' : {
'relPath' : '/yongwon-h/main.do',
're' : <RegExp>[
RegExp(r'<h2 class="tit_1">(.|\n|\r|\u2028|\u2029)*?<h2 class="tit_2">'),
RegExp(r'<li><a.+>(.+)<\/a>(.|\n|\r|\u2028|\u2029)*?(\d{4}\.\d\d\.\d\d)'),
]
},
'images' : {
'relPath' : '/yongwon-h/na/ntt/selectNttList.do?mi=73747&&bbsId=62865',
're' : <RegExp>[
RegExp(r'<div class="photo_list">(.|\n|\r|\u2028|\u2029)*?<!-- \/\/게시판 리스트'),
RegExp(r'<img src="(.+)" onerror'),
]
},
};
class Yongwon {
static const _baseUrl = 'http://yongwon-h.gne.go.kr';
static FutureOr<void> fetchNoticies() async {
await _getHTMLObjects(
reDic['notices']!['relPath'],
reDic['notices']!['re']![0],
reDic['notices']!['re']![1],
)
.then((matches) {
if (matches != null) {
matches.forEach((match) => print('${match.group(1)} ..... ${match.group(3)}'));
}
});
}
static FutureOr<void> fetchImages() async {
await _getHTMLObjects(
reDic['images']!['relPath'],
reDic['images']!['re']![0],
reDic['images']!['re']![1],
)
.then((matches) {
if (matches != null) {
matches.forEach((match) => print('$_baseUrl${match.group(1)}'));
}
});
}
static Future<Iterable<RegExpMatch>?> _getHTMLObjects(String relPath, RegExp reContainer, RegExp reObjects) async {
var page = await NetService.getRaw(_baseUrl + relPath)
.whenComplete(() => print('Page done.\n'));
if (page != null) {
final objectsPane = reContainer.firstMatch(page)!.group(0);
if (objectsPane != null) {
return Future.value(reObjects.allMatches(objectsPane));
}
}
return null;
}
}
void main(List<String> args) async {
await Yongwon.fetchImages();
print('\nJob done!');
}
Netservice (partial code):
class NetService {
static Future<String?> getRaw(String url, {int okCode = 200}) {
return http.get(Uri.parse(url))
.then((response) {
if (response.statusCode == okCode) {
return response.body;
}
PrintService.showDataNotOK(response);
return null;
})
.catchError((err) => PrintService.showError(err));
}
}
Result:
Page done.
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_85189591/thumb/thumb_img_9028b523-7bfb-466f-848c-65870a93b99c1616411595463.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_85169237/thumb/thumb_img_0fe7d01b-6941-4468-8623-088af971fbf21616047569744.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_85148970/thumb/thumb_img_67ae1c34-cd49-4af4-8a68-cacec672c84d1615859096270.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_85041266/thumb/thumb_img_ddc5097b-ae4e-4190-b0b8-1aa88cf78e491614223854604.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_85039068/thumb/thumb_img_f5c77ec4-a448-44b0-b5b1-61079be18eb61614145925749.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_85002051/thumb/thumb_img_0df44e4d-9872-4605-a94f-32b3004bc42a1612331543446.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_84955511/thumb/thumb_img_de1fc864-2689-4917-85bc-b5d714040b1f1610248949513.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_84950100/thumb/thumb_img_cd3270ee-7bd0-4601-81fc-2de446903e281609919353000.jpg
http://yongwon-h.gne.go.kr/upload/bbs/files/2021/hgschl/yongwon-h/ntt/62865/ntt_84950096/thumb/thumb_img_0eee718a-a2de-4182-a0d9-f97de17d98741609919173296.jpg
Job done!

How to use single Icon button to play and pause audio in flutter

How I can use single IconButton to play and pause the audio in flutter, using audio play package. Also if Icon I click on single list item it should change only one icon not all list icons.
And if anyone can suggest best audio player package to play list with inline audio it will be helpful.
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:gradient_app_bar/gradient_app_bar.dart';
import 'package:http/http.dart' as http;
import 'package:jummamubarak/Screens/HomeScreen.dart';
import 'package:jummamubarak/Screens/ViewTone.dart';
class TonesListScreen extends StatefulWidget {
#override
_TonesListScreenState createState() => _TonesListScreenState();
}
class _TonesListScreenState extends State<TonesListScreen> {
final String data =
"https://api.airtable.com/v0/appZeBnQJQ0OaVoPQ/Ringtones?maxRecords=100000&view=Tones";
List toneTitle;
List toneurl;
ScrollController _controller = new ScrollController();
#override
void initState() {
super.initState();
this.getJsonData();
}
Future<String> getJsonData() async {
var response = await http.get(
Uri.encodeFull(data),
headers: {
HttpHeaders.contentTypeHeader: "application/json",
HttpHeaders.authorizationHeader: "Bearer keyr05is7vPCWxmYM"
},
// headers: {"Accept": "application/json"},
);
print(response.body);
setState(() {
// ignore: non_constant_identifier_names
var ConvertDataToJson = json.decode(response.body);
toneTitle = ConvertDataToJson['records'];
});
setState(() {
// ignore: non_constant_identifier_names
var ConvertDataToJson = json.decode(response.body);
toneurl = ConvertDataToJson['records'];
});
return "Success";
}
Widget _files() {
if (toneTitle == null) {
return SpinKitCircle(
color: Color(0xff34495E),
size: 50.0,
);
} else {
return ListView.builder(
physics: const AlwaysScrollableScrollPhysics(), // new
controller: _controller,
itemCount: toneTitle == null ? 0 : toneTitle.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0),
child: Card(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: Text(
toneTitle.reversed.toList()[index]['fields']['Name'],
style: GoogleFonts.muli(
fontSize: 15.0,
fontWeight: FontWeight.bold,
),
),
),
RadiantGradientMask(
child: IconButton(
icon: Icon(
Icons.play_circle_filled,
color: Colors.white,
size: 40.0,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ViewTone(
toneTitle: toneTitle.reversed.toList()[index]
['fields']['Name'],
toneUrl: toneurl.reversed.toList()[index]
['fields']['Url'],
),
),
);
},
),
)
],
),
),
),
);
},
);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: GradientAppBar(
gradient: LinearGradient(
colors: [
Color(0xff14d5a3),
Color(0xff039cc1),
],
),
title: Text(
'Islamic Tones',
style: GoogleFonts.muli(
fontWeight: FontWeight.bold,
),
),
),
body: _files(),
);
}
}
``
An audio player plugin that you can use in Flutter is audioplayers plugin. Simply initialize AudioPlayer to use functions play(), pause(), resume(), and stop(). Determine when you're going to play the audio from start and when pause/resume will be called on your use case. You can initialize a Timer each when the audio is played. If Timer is still set to 0, play the audio from the beginning. Else, call play/resume.
AudioPlayer audioPlayer = AudioPlayer();
// Call to play audio from the beginning
_playStart() async {
int result = await audioPlayer.play(url);
if (result == 1) {
// success
}
}
// Call to pause and resume audio
_playPause(bool play) async {
if(play){
await audioPlayer.resume();
} else {
await audioPlayer.pause();
}
}
// use the button with the help of index then it work properly
int? ind;
buildPlayPauseButton(RssEnclosure? enclosure, int index) {
return IconButton(
onPressed: () async {
await player.setUrl(enclosure!.url.toString());
(ind == index) ? player.pause() : player.play();
setState(() {
ind = index;
});
},
icon: (ind == index)
? const Icon(Icons.pause)
: const Icon(Icons.play_arrow),
);
}

Flutter image_picker package returns null when trying to retrieve a video from the gallery

I am trying to build an app that lets users select videos and upload them, so for this, I am using the image_picker package. However, I am currently running tests and whenever I try to select a video from the gallery, instead of getting a file back I get null. I don't know if the problem is with how I am using the package or with permissions, although according to the package you don't need permissions for android.
Below the function in my code that is giving me trouble:
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
);
//This line always returns false
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
The complete code (minus completely irrelevant things):
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:golfapp/data/course_data.dart';
import 'package:golfapp/data/user_data.dart';
import 'package:provider/provider.dart';
import 'package:image_picker/image_picker.dart';
import 'package:uuid/uuid.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:golfapp/data/semana_data.dart';
import 'package:golfapp/widgets/chewie_item.dart';
final StorageReference storageRef = FirebaseStorage.instance.ref();
final postsRef = Firestore.instance.collection('posts');
final DateTime timestamp = DateTime.now();
class DetailScreen extends StatefulWidget {
final int index;
final String photoUrl;
final String videoUrl;
DetailScreen({this.index, this.photoUrl, this.videoUrl});
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
bool isUploading = false;
bool selected = false;
List<File> files = [];
String postId = Uuid().v4();
TextEditingController captionController = TextEditingController();
showError() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Row(
children: [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: Text('Error'),
),
Icon(Icons.error_outline, size: 60.0),
],
),
content: SingleChildScrollView(
child: ListBody(
children: [
Text(
'Hubo un error con el video seleccionado.',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.w600,
fontSize: 17.0,
),
),
],
),
),
);
},
);
}
clearImage() {
setState(() {
this.selected = false;
});
}
handleTakePhoto() async {
Navigator.pop(context);
File fileTaken = await ImagePicker.pickVideo(
source: ImageSource.camera,
maxDuration: Duration(seconds: 90),
);
setState(() {
if (fileTaken != null) {
this.files.add(fileTaken);
this.selected = true;
} else {
showError();
}
});
}
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
);
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
selectImage(parentContext) {
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Seleccionar video"),
children: <Widget>[
SimpleDialogOption(
child: Text("Tomar video"),
onPressed: handleTakePhoto,
),
SimpleDialogOption(
child: Text("Video de la galería"),
onPressed: handleChooseFromGallery,
),
SimpleDialogOption(
child: Text("Cancelar"),
onPressed: () => Navigator.pop(context),
)
],
);
},
);
}
Future<String> uploadVideo(imageFile) async {
StorageUploadTask uploadTask = storageRef
.child(Provider.of<UserData>(context, listen: false).user.id)
.child(Provider.of<CourseData>(context, listen: false).course.uid)
.child(Provider.of<SemanaData>(context, listen: false).semana.uid)
.putFile(imageFile, StorageMetadata(contentType: 'video/mp4'));
StorageTaskSnapshot storageSnap = await uploadTask.onComplete;
String downloadUrl = await storageSnap.ref.getDownloadURL();
return downloadUrl;
}
createPostInFirestore({List<String> mediaUrl, String description}) {
postsRef
.document(Provider.of<UserData>(context, listen: false).user.id)
.collection("userPosts")
.document(Provider.of<CourseData>(context, listen: false).course.uid)
.setData({
"semana": Provider.of<SemanaData>(context, listen: false).semana.uid,
"postId": postId,
"ownerId": Provider.of<UserData>(context, listen: false).user.id,
"username": Provider.of<UserData>(context, listen: false).user.username,
"mediaUrl": mediaUrl,
"description": description,
"timestamp": timestamp,
"likes": {},
});
}
handleSubmit() async {
setState(() {
isUploading = true;
});
List<String> mediaUrlS = [];
for (File fileLoop in files) {
String mediaUrl = await uploadVideo(fileLoop);
mediaUrlS.add(mediaUrl);
}
createPostInFirestore(
mediaUrl: mediaUrlS,
description: captionController.text,
);
captionController.clear();
setState(() {
files = [];
isUploading = false;
postId = Uuid().v4();
selected = false;
});
}
Scaffold buildUploadForm() {
return Scaffold(
appBar: AppBar(
title: Text(
"Tu video",
style: TextStyle(color: Colors.black),
),
actions: [
FlatButton(
onPressed: files.length < 2 ? selectImage(context) : null,
child: Text(
'Seleccionar otro video',
),
),
FlatButton(
onPressed: isUploading ? null : () => handleSubmit(),
child: Text(
"Mandar",
),
),
],
),
body: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: files.length,
itemBuilder: (BuildContext context, int index) {
final File fileBuilder = files[index];
return Container(
height: 220.0,
width: MediaQuery.of(context).size.width * 0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
child: ChewieListItem(
videoUrl: fileBuilder.path,
network: false,
file: fileBuilder,
),
),
),
),
);
}),
);
}
Widget buildNormalScreen () {
return Container(
child: GestureDetector(
onTap: () {
selectImage(context);
},
child: Container(
height: 50.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Theme.of(context).accentColor,
),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Subir videos',
style: TextStyle(
fontFamily: 'Comfortaa',
fontSize: 17.0,
color: Colors.white,
),
),
],
),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return !selected
? buildNormalScreen()
: buildUploadForm();
}
}
In the function at the top, I also tried doing something like ImagePicker.pickVideo().then((file){...}) but it didn't work.
I also added <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> to my "android/app/src/main/AndroidManifest.xml" file.
I also tried adding android:requestLegacyExternalStorage="true" inside the <application> tag in my "android/app/src/main/AndroidManifest.xml" file, but then I get an error:
I don't know what I should be changing either in my code or in one of the files in the android folder, any help is deeply appreciated.
Thank you very much in advance
Put the condition in the same function.
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
//This line always returns false
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
);