flutter: just_audio player plugin seekToNext and seekToPrevious - flutter

Im new to flutter and Im creating a music player using just_audio plugin but I having trouble implementing the nxt button where I want to change the song that currently playing.
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: item.data!.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(item.data![index].title),
trailing: IconButton(
icon: const Icon(Icons.play_arrow),
onPressed: () {
playmusichandler('${item.data![index].uri}');
},
),
t
void playmusic() async{
try {
await widget.audioPlayer
.setAudioSource(AudioSource.uri(Uri.parse(widget.songModel.uri!)));
await widget.audioPlayer.play();
} catch (e) {
debugPrint('$e');
}
}
==
StreamBuilder<SequenceState?>(
stream: widget.audioPlayer.sequenceStateStream,
builder: (context, index) {
return IconButton(
onPressed: () {
widget.audioPlayer.hasNext
? widget.audioPlayer.seekToNext()
: null;
},
icon: const Icon(
Icons.skip_next,
size: 45.0,
color: Colors.white,
));
}),

It is important to note that here you are working with audio clips which means you are using single songs. Nevertheless, a playlist is another option available in the just_audio package.
Working with gapless playlists.
`// Define the playlist
final playlist = ConcatenatingAudioSource(
// Start loading next item just before reaching it
useLazyPreparation: true,
// Customise the shuffle algorithm
shuffleOrder: DefaultShuffleOrder(),
// Specify the playlist items
children: [
AudioSource.uri(Uri.parse('https://example.com/track1.mp3')),
AudioSource.uri(Uri.parse('https://example.com/track2.mp3')),
AudioSource.uri(Uri.parse('https://example.com/track3.mp3')),
],
);
// Load and play the playlist
await player.setAudioSource(playlist, initialIndex: 0, initialPosition: Duration.zero);
await player.seekToNext(); // Skip to the next item
await player.seekToPrevious(); // Skip to the previous item
await player.seek(Duration.zero, index: 2); // Skip to the start of track3.mp3
await player.setLoopMode(LoopMode.all); // Set playlist to loop (off|all|one)
await player.setShuffleModeEnabled(true); // Shuffle playlist order (true|false)
// Update the playlist
await playlist.add(newChild1);
await playlist.insert(3, newChild2);
await playlist.removeAt(3);`
When you are dealing with children, you have to pass the audio list to them. Following that, you can use the index to determine which song will play when you select a song, then you can choose to play previous or other options

Related

Show list of all videos from internal storage

list all video files from a specific folder from internal storage and display them in flutter.
i want to create an app to list all videos in internal storage and show them in gridview and play that video
To get all the files from the storage you can use path_provider flutter package. With this, get the folder path, extract all the files with an extension of .mp4 (video file), and store it in List.
List<FileSystemEntity> _files = [];
void _getFiles() async {
Directory directory = await getExternalStorageDirectory();
List<FileSystemEntity> files = directory.listSync().where((entity) => entity.path.endsWith('.mp4')).toList();
setState(() {
_files = files;
});
}
Then you can use video_player Flutter package to play the video.
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1,
),
itemCount: _files.length,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
setState(() {
_controller = VideoPlayerController.file(_files[index])
..initialize().then((_) {
_controller.play();
});
});
},
child: Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.video_library,
size: 50,
),
SizedBox(height: 10),
Text(_files[index].path.split('/').last),
],
),
),
);
},
);

how to show circular progress indicator while uploading multiple images to firebase using two screens

i am making a house management app i have to upload images of the property alongside other data related to the property so i am using two screens one for the general info about the house and the second one specifically to upload images
Form screen
Image Upload Screen
from the upload screen i am returning back a list of images to the form screen
// i am waiting for the list in the form screen
images = await Navigator.push(context, MaterialPageRoute(builder: (context) => AddPictures()));
// i am returning the list back from the upload screen
Navigator.pop(context,imageStrings);
I am failing to show circular progress indicator for some reason beyond my capacity to know itried all ways i know
this is the rest of the code
//outiside the widdget build i have two lists
List<XFile> imagesXFiles = []; //for raw image files from the gallery or camera
List<String> imageStrings = []; //for image links from the firebase storage
body: isLoading == true ? CircularProgressIndicator() : Column(
children: [
Expanded(
//the first grid is a button to let the user access camera or gallery
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 2.0,
mainAxisSpacing: 2.0
),
itemCount: imagesXFiles.length + 1,
itemBuilder: (BuildContext context, int index) {
return index == 0 ? GestureDetector(
onTap: (){
// a function to pick images and add store them to the list "imagesXFiles"
_showPicker(context);
},
child: Container(
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.circular(5.0),
),
child: Icon(
Icons.add,
color: Colors.black,
size: 30.0,
),
),
): Container(
child: Image(
image: FileImage(File(imagesXFiles[index-1].path)),
fit: BoxFit.fill
),
);
},
),
),
TextButton(
onPressed: ()async{
// for some reason the circular progress doesn't work i dont understand why
setState(() {
isLoading = true;
});
imageStrings = await uploadImages(imagesXFiles).whenComplete(() {
setState(() {
isLoading = false;
Navigator.pop(context,imageStrings);
});
});
},
child: Text("Upload",style: TextStyle(color: Colors.black,fontSize: 25),)),
],
),
here is the upload function that uploads the images to firebase
Future<List<String>> uploadImages(List<XFile> imagesXFiles) async {
imagesXFiles.forEach((image) async {
final storageRef = storage.ref().child(Random().nextInt(100).toString());
await storageRef.putFile(File(image.path));
String imageURL = await storageRef.getDownloadURL();
imageStrings.add(imageURL);
firebaseFirestore
.collection("housePictures")
.add({
"imageURL" : imageURL,
});
});
return imageStrings;
}
You can use forEach with Future as below.
await Future.forEach(imagesXFiles, (image) async {
final storageRef = storage.ref().child(Random().nextInt(100).toString());
await storageRef.putFile(File(image.path));
String imageURL = await storageRef.getDownloadURL();
imageStrings.add(imageURL);
FirebaseFirestore.instance
.collection("housePictures")
.add({
"imageURL" : imageURL,
});
});
You can’t use forEach statement in an async operation. It is not going to wait. Use a normal for statement. Example: for(var item in items) etc. That should fix your issue. If you really want to use a for each you need to use Future. foreach see this thread -> How to Async/await in List.forEach() in Dart

Flutter Firebase Storage Data doesn't show Data immediately

I'm currently working on a project in flutter where I want to store uploaded Data in Firebase Storage. This works fine but now I'm facing a problem with showing the data. I have to do a restart for showing the uploaded Data in my List.
I hope someone can help me with this issue.
onPressed: () async {
FilePickerResult? result = await FilePicker.platform
.pickFiles(allowMultiple: true);
if (result == null) return;
final path = result.files.single.path!;
setState(() {
});
final fileName = result.files.single.name;
storage
.uploadFile(path, fileName)
.then((value) => print('Done'));
},
This is my call function when pressing the button.
Future<void> uploadFile(String destination, String fileName) async {
final User? user = auth.currentUser;
final uid = user!.uid;
File file = File(destination);
try {
await storage.ref('$uid/$fileName').putFile(file);
} on firebase_core.FirebaseException catch (e) {
print(e);
}
}
This is my method for pushing the data into firebase storage.
Container(
width: MediaQuery.of(context).size.width - 15,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
),
child: FutureBuilder(
future: _loadImages(),
builder: (context,
AsyncSnapshot<List<Map<String, dynamic>>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Row(
children: [
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data?.length ?? 0,
itemBuilder: (context, index) {
final Map<String, dynamic> image =
snapshot.data![index];
return Card(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20)),
elevation: 0,
child: ListTile(
dense: false,
contentPadding: EdgeInsets.all(15),
leading: Image.network(
image['url'],
),
trailing: IconButton(
onPressed: () => _delete(image['path']),
icon: const Icon(
Icons.delete,
color: Colors.red,
),
),
),
);
},
),
),
],
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
),
And this is how I display my files in my app.
Looking forward for some help.
I want to see my data directly when uploading it into Firebase Storage.
If you want to show the newly uploaded image right away, you will have to force a refresh of the code that renders the list of images. If you're using a StatefulWidget to render the images, you could for example call setState() on that widget after the upload has completed. If you're using another state management approach, you'd do the equivalent for that approach.
But note that this will only work on the device of the user who uploaded the image. Any other devices will still only see the new image if they manually restart the rendering of the list of images.
A common way to work around this is to store the list of image URLs in one of Firebase's databases (Realtime Database or Cloud Firestore), and render it from there with a StreamBuilder. The StreamBuilder continues to listen for updates to the database, so if one user's image upload completes and they write the URL/path of the image to the database, that immediately refreshes the list of images not just on their device, but on all other connected devices too.

How to render image from Firebase without rebuilding?

I'm trying to implement profile image picking in my flutter app using Firebase Storage. I use image_picker to get the image and upload it to Firebase, get the download link and add the download link to the imgsrc field in the cloud firestore, from where I can render the NetworkImage.
Center(
child: Stack(
children: [
buildImage(),
Positioned(
bottom: 5,
right: 5,
child: GestureDetector(
onTap: showPhotoAlertDialog,
child: buildEditIcon(Color(0xff407bff))),
),
],
),
),
How can I get the default Icons.person kind image for when the user has no profile image, and get the image from the database otherwise?
The code I'm using right now is as follows:
Widget buildImage() {
return CircleAvatar(
backgroundImage: NetworkImage(loggedInUser.imgsrc ??
'https://th.bing.com/th/id/R.945f33b643f2ceffcdae90fb57c61854?rik=XcI0SYBgSefoCA&riu=http%3a%2f%2fgetdrawings.com%2ffree-icon-bw%2fanonymous-avatar-icon-19.png&ehk=5n%2buJG66CeLQZsmhaMt8gag5rXuM3TdebAL6W35K1E4%3d&risl=&pid=ImgRaw&r=0'),
backgroundColor: Colors.grey[350],
radius: 100,
);
}
I created an Alert Dialog widget to choose whether to choose the image from camera or from the gallery.
showPhotoAlertDialog() {
AlertDialog alert = AlertDialog(
title: Text("Upload from"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextButton(
onPressed: () {
imageFromCamera()
.then((value) => uploadFile())
.whenComplete(() => postSource());
setState(() {}); ----->
},
child: Text("Upload from camera"),
),
TextButton(
onPressed: () {
imageFromGallery().then((value) => uploadFile());
postSource();
setState(() {});
},
child: Text("Upload from gallery"),
)
],
),
);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
To upload the image to storage and post the source to cloud firestore, I use the following methods:
Future uploadFile() async {
if (file == null) return;
final fileName = path.basename(file!.path);
final destination = 'files/$fileName';
task = FirebaseApi.uploadFile(destination, file!);
setState(() {});
if (task == null) return;
final snapshot = await task!.whenComplete(() {});
urlDownload = await snapshot.ref.getDownloadURL();
print('Download-Link: $urlDownload');
}
postSource() async {
FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
await firebaseFirestore
.collection("users")
.doc(user?.uid)
.update({'imgsrc': urlDownload});
}
The link gets uploaded properly and I'm able to get the link in my NetworkImage, but it doesn't get rendered immediately. I have to close the parent drawer and open it again to get it. I call setState(){} as well after posting the source, but it doesn't make any difference. How can I get the image without having to close and open the drawer?
Any help would be appreciated!
Thanks
You also have to update image in model class or in this imgsrc also just add this line above setState in onPressed of TextButton.
loggedInUser.imgsrc = urlDownload;

Favourite Button in Flutter got unFavourited on Relaunch app

I have a ListView Item with Favourite icon and I want to add functionality so that I can add list into favourite list. data is successfully added to favourite list.
Here is HomePage
body: ListView.builder(
itemCount: 100,
cacheExtent: 20.0,
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (context, index) => ItemTile(index),
),
and My ListTile class I used
var favoritesList = Provider.of<Favorites>(context);
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.primaries[index % Colors.primaries.length],
),
title: Text(
'Item $index',
key: Key('text_$index'),
),
trailing: IconButton(
key: Key('icon_$index'),
icon: favoritesList.items.contains(index)
? Icon(Icons.favorite, color: Colors.redAccent)
: Icon(Icons.favorite_border),
onPressed: () {
!favoritesList.items.contains(index)
? favoritesList.add(index)
: favoritesList.remove(index);
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(favoritesList.items.contains(index)
? 'Added to favorites.'
: 'Removed from favorites.'),
duration: Duration(seconds: 1),
),
);
},
),
),
I have a model class favourites.dart
class Favorites extends ChangeNotifier {
final List<int> _favoriteItems = [];
List<int> get items => _favoriteItems;
void add(int itemNo) {
_favoriteItems.add(itemNo);
notifyListeners();
}
void remove(int itemNo) {
_favoriteItems.remove(itemNo);
notifyListeners();
}
}
and in my favouritePage. I am getting everything perfect and also can remove favourited item but when I reopen my app I did not get any favourited item.
here is my page FavouritePage.
body: Consumer<Favorites>(
builder: (context, value, child) => ListView.builder(
itemCount: value.items.length,
padding: const EdgeInsets.symmetric(vertical: 16),
itemBuilder: (context, index) => FavoriteItemTile(value.items[index]),
),
),
FavouriteItemTile
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
),
title: Text(
'Item $itemNo',
key: Key('favorites_text_$itemNo'),
),
trailing: IconButton(
key: Key('remove_icon_$itemNo'),
icon: Icon(Icons.close),
onPressed: () {
Provider.of<Favorites>(context, listen: false).remove(itemNo);
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Removed from favorites.'),
duration: Duration(seconds: 1),
),
);
},
),
),
please provide the solution and can I use shared preferences with provider.
Yes. You should be using SharedPreferences. Add the preference library and these pieces of code
Object.dart
class Object1{
bool isLiked;
String name;
const Object1(this.name,this.isLiked);//Whatever fields you need
factory User.fromJson(Map<String, dynamic> parsedJson) {
return new Object1(
name: parsedJson['name'] ?? "",
isLiked: parsedJson['isLiked'] ?? "");
}
Map<String, dynamic> toJson() {
return {
"name": this.name,
"isLiked": this.isLiked
};
}
}
Main.dart
void main(){
setData();
runApp(MyApp);
}
void setData() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
List dataList = [Object1("Name",false).toJson()];//Your items in this format
if prefs.getStringList("lists") == null:
Map decode_options = jsonDecode(dataList);
prefs.setStringList(jsonEncode(Object1.fromJson(decode_options)));
}
Now instead of a custom class for favourites, we will get all the data where we can filter. To retrieve the data afterwards, use this code
SharedPreferences prefs = await SharedPreferences.getInstance();
Map objectMap = jsonDecode(await shared_User.getStringList('list'));
List itemList = [];
for (item in objectMap):
itemList.append(User.fromJson(item));
Now you can use this Item list with the properties and the isLiked feature which is a boolean to check whether it is showed or not.
This may seem complicated but is perfectly simple though your work would be much easier if you used a database like firebase and stored these as documents
One option can be that you can store according to index value in shared preference and query that index value in order to see whether it is added as favourite or not. However it won't be efficient as the number of favourites increases, though still an option.
If you want to store on device us File(pathToFile).write(dataAsString)
You might want to save the data as json using jsonEncode(listOfNumbers) and decode using jsonDecode()
Explanation:
To save data, convert it to json and save to File on device
// NOTE: dataAsMap should be instance of class Map which stores the data you want to save
Directory localDirectory = await getApplicationDocumentsDirectory();
File(localDirectory.path + “/“ + “fileName.json”).writeAsStringSync(jsonEncode(dataAsMap));
To get data:
Map jsonData = jsonDecode(File(localDirectory.path + “/“ + “fileName.json”).readAsStringSync())