Play audio through earpiece in flutter , is it possible now, is there any plugin available for this use Case
import 'dart:math';
import 'package:audio_session/audio_session.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart' as ja;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final _player = ja.AudioPlayer(
// Handle audio_session events ourselves for the purpose of this demo.
handleInterruptions: false,
androidApplyAudioAttributes: false,
handleAudioSessionActivation: false,
);
#override
void initState() {
super.initState();
AudioSession.instance.then((audioSession) async {
// This line configures the app's audio session, indicating to the OS the
// type of audio we intend to play. Using the "speech" recipe rather than
// "music" since we are playing a podcast.
await audioSession.configure(AudioSessionConfiguration(
avAudioSessionCategory: AVAudioSessionCategory.playback,
avAudioSessionCategoryOptions:
AVAudioSessionCategoryOptions.allowBluetooth,
avAudioSessionMode: AVAudioSessionMode.defaultMode,
avAudioSessionRouteSharingPolicy:
AVAudioSessionRouteSharingPolicy.independent,
avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none,
androidAudioAttributes: const AndroidAudioAttributes(
contentType: AndroidAudioContentType.unknown,
flags: AndroidAudioFlags.none,
usage: AndroidAudioUsage.media,
),
androidAudioFocusGainType: AndroidAudioFocusGainType.gain,
androidWillPauseWhenDucked: false,
));
// Listen to audio interruptions and pause or duck as appropriate.
_handleInterruptions(audioSession);
// Use another plugin to load audio to play.
await _player.setUrl(
"https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3");
});
}
void _handleInterruptions(AudioSession audioSession) {
// just_audio can handle interruptions for us, but we have disabled that in
// order to demonstrate manual configuration.
bool playInterrupted = false;
audioSession.becomingNoisyEventStream.listen((_) {
print('PAUSE');
_player.pause();
});
_player.playingStream.listen((playing) {
playInterrupted = false;
if (playing) {
audioSession.setActive(true);
}
});
audioSession.interruptionEventStream.listen((event) {
print('interruption begin: ${event.begin}');
print('interruption type: ${event.type}');
if (event.begin) {
switch (event.type) {
case AudioInterruptionType.duck:
if (audioSession.androidAudioAttributes!.usage ==
AndroidAudioUsage.game) {
_player.setVolume(_player.volume / 2);
}
playInterrupted = false;
break;
case AudioInterruptionType.pause:
case AudioInterruptionType.unknown:
if (_player.playing) {
_player.pause();
playInterrupted = true;
}
break;
}
} else {
switch (event.type) {
case AudioInterruptionType.duck:
_player.setVolume(min(1.0, _player.volume * 2));
playInterrupted = false;
break;
case AudioInterruptionType.pause:
if (playInterrupted) _player.play();
playInterrupted = false;
break;
case AudioInterruptionType.unknown:
playInterrupted = false;
break;
}
}
});
audioSession.devicesChangedEventStream.listen((event) {
print('Devices added: ${event.devicesAdded}');
print('Devices removed: ${event.devicesRemoved}');
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('audio_session example'),
),
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Center(
child: StreamBuilder<ja.PlayerState>(
stream: _player.playerStateStream,
builder: (context, snapshot) {
final playerState = snapshot.data;
if (playerState?.processingState !=
ja.ProcessingState.ready) {
return Container(
margin: EdgeInsets.all(8.0),
width: 64.0,
height: 64.0,
child: CircularProgressIndicator(),
);
} else if (playerState?.playing == true) {
return IconButton(
icon: Icon(Icons.pause),
iconSize: 64.0,
onPressed: _player.pause,
);
} else {
return IconButton(
icon: Icon(Icons.play_arrow),
iconSize: 64.0,
onPressed: _player.play,
);
}
},
),
),
),
Expanded(
child: FutureBuilder<AudioSession>(
future: AudioSession.instance,
builder: (context, snapshot) {
final session = snapshot.data;
if (session == null) return SizedBox();
return StreamBuilder<Set<AudioDevice>>(
stream: session.devicesStream,
builder: (context, snapshot) {
final devices = snapshot.data ?? {};
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Input devices",
style: Theme.of(context).textTheme.headline6),
for (var device
in devices.where((device) => device.isInput))
Text(
'${device.name} (${describeEnum(device.type)})'),
SizedBox(height: 16),
Text("Output devices",
style: Theme.of(context).textTheme.headline6),
for (var device
in devices.where((device) => device.isOutput))
Text(
'${device.name} (${describeEnum(device.type)})'),
],
);
},
);
},
),
),
],
),
),
),
);
}
}
if you implement the above functionality already , Please mention a solution
used plugins
just_audio: ^0.9.24
audio_session: ^0.1.7
Flutter 3.0.1 • channel stable Tools • Dart 2.17.1 • DevTools 2.12.2
Related
I'm developing an app using movies database API. I want to read a list of the movies and then choose one and display the details to user.
MovieDetailsBloc code:
import 'package:bloc/bloc.dart';
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_recruitment_task/movie_details/models/movie_details.dart';
import 'package:flutter_recruitment_task/services/api_service.dart';
import 'package:stream_transform/stream_transform.dart';
part 'movie_details_event.dart';
part 'movie_details_state.dart';
const throttleDuration = Duration(milliseconds: 100);
EventTransformer<E> throttleDroppable<E>(Duration duration) {
return (events, mapper) {
return droppable<E>().call(events.throttle(duration), mapper);
};
}
class MovieDetailsBloc extends Bloc<MovieDetailsEvent, MovieDetailsState> {
MovieDetailsBloc({required this.apiService}) : super(MovieDetailsState()) {
on<MovieSelected>(
_onMovieSelected,
transformer: throttleDroppable(throttleDuration),
);
}
final ApiService apiService;
Future<void> _onMovieSelected(MovieSelected event, Emitter<MovieDetailsState> emit) async {
try{
final movie = await _fetchMovieDetails(event.query);
return emit(state.copyWith(
status: MovieDetailsStatus.success,
movie: movie,
));
} catch (_) {
emit(state.copyWith(status: MovieDetailsStatus.failure));
}
}
Future<MovieDetails> _fetchMovieDetails(String id) async {
final movie = apiService.fetchMovieDetails(id);
return movie;
}
String shouldIWatchIt() {
final movie = state.movie;
if(movie.revenue - movie.budget > 1000000 && DateTime.now().weekday == DateTime.sunday){
return 'Yes';
} else {
return 'No';
}
}
}
MovieListPage code:
import 'package:flutter/material.dart';
import 'package:flutter_recruitment_task/movie_details/bloc/movie_details_bloc.dart';
import 'package:flutter_recruitment_task/movies/bloc/movies_bloc.dart';
import 'package:flutter_recruitment_task/movies/models/movie.dart';
import 'package:flutter_recruitment_task/pages/movie_details/movie_details_page.dart';
import 'package:flutter_recruitment_task/pages/movie_list/movie_card.dart';
import 'package:flutter_recruitment_task/pages/movie_list/search_box.dart';
import 'package:flutter_recruitment_task/services/api_service.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MovieListPage extends StatefulWidget {
#override
_MovieListPage createState() => _MovieListPage();
}
class _MovieListPage extends State<MovieListPage> {
final ApiService apiService = ApiService();
late final MoviesBloc moviesBloc;
late final MovieDetailsBloc movieDetailsBloc;
void _onSearchBoxSubmitted(String text) {
moviesBloc.add(MoviesFetched(query: text));
}
#override
void initState() {
moviesBloc = MoviesBloc(apiService: apiService);
movieDetailsBloc = MovieDetailsBloc(apiService: apiService);
super.initState();
}
#override
void dispose() {
movieDetailsBloc.close();
moviesBloc.close();
super.dispose();
}
#override
Widget build(BuildContext context) => BlocProvider(
create: (_) => movieDetailsBloc,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.movie_creation_outlined),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => MovieDetailsPage(
movieDetailsBloc: movieDetailsBloc,
)
)
);
},
),
],
title: Text('Movie Browser'),
),
body: BlocProvider(
create: (_) => moviesBloc,
child: Column(
children: <Widget>[
SearchBox(onSubmitted: _onSearchBoxSubmitted),
Expanded(child: _buildContent()),
],
),
),
),
);
Widget _buildContent() => BlocBuilder<MoviesBloc, MoviesState>(
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
switch (state.status) {
case MoviesStatus.failure:
return const Center(child: Text('failed to fetch movies'));
case MoviesStatus.success:
if (state.movies.isEmpty) {
return const Center(child: Text('no movies'));
}
return _buildMoviesList(state.movies);
case MoviesStatus.initial:
return const Center(child: CircularProgressIndicator());
}
});
Widget _buildMoviesList(List<Movie> movies) => ListView.separated(
separatorBuilder: (context, index) => Container(
height: 1.0,
color: Colors.grey.shade300,
),
itemBuilder: (context, index) => BlocBuilder<MovieDetailsBloc, MovieDetailsState>(
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
return MovieCard(
title: movies[index].title,
rating: '${(movies[index].voteAverage * 10).toInt()}%',
color: state.movie.title == movies[index].title ?
Colors.amberAccent : Colors.white,
onTap: () {
movieDetailsBloc.add(MovieSelected(query: movies[index].id.toString()));
},
);
}
),
itemCount: movies.length,
);
}
MovieDetailsPage code:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_recruitment_task/movie_details/bloc/movie_details_bloc.dart';
import 'package:flutter_recruitment_task/movie_details/models/movie_detail_placeholder.dart';
class MovieDetailsPage extends StatefulWidget {
final MovieDetailsBloc? movieDetailsBloc;
const MovieDetailsPage({super.key, this.movieDetailsBloc});
#override
_MovieDetailsPageState createState() => _MovieDetailsPageState();
}
class _MovieDetailsPageState extends State<MovieDetailsPage> {
var _details = [];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) => BlocProvider(
create: (_) => widget.movieDetailsBloc!,
child: BlocBuilder<MovieDetailsBloc, MovieDetailsState>(
buildWhen: (previous, current) => previous != current,
builder: (context, state) {
_details = [
MovieDetailPlaceholder(title: 'Budget', content: '\$ ${state.movie.budget}'),
MovieDetailPlaceholder(title: 'Revenue', content: '\$ ${state.movie.revenue}'),
MovieDetailPlaceholder(title: 'Should I watch it today?', content: widget.movieDetailsBloc!.shouldIWatchIt()),
];
return Scaffold(
appBar: AppBar(
title: Text(state.movie.title),
),
body: ListView.separated(
separatorBuilder: (context, index) => Container(
height: 1.0,
color: Colors.grey.shade300,
),
itemBuilder: (context, index) => Container(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
_details[index].title,
style: Theme.of(context).textTheme.headline5,
),
SizedBox(height: 8.0),
Text(
_details[index].content,
style: Theme.of(context).textTheme.subtitle1,
),
],
),
),
itemCount: _details.length,
),
);
}
),
);
}
I'm passing an instance of BLoC from MovieListPage to MovieDetailsPage because it holds the details of the movie to display. It works fine for one time, however when I go back to the MovieListPage I'm not able to choose a new movie to display the details. How I can make an instance of BLoC persist through navigation?
Create your bloc's intance after your bloc ends like
class MovieDetailsBloc extends Bloc<MovieDetailsEvent, MovieDetailsState> {
MovieDetailsBloc({required this.apiService}) : super(MovieDetailsState()) {
on<MovieSelected>(
_onMovieSelected,
transformer: throttleDroppable(throttleDuration),
);
}
final ApiService apiService;
Future<void> _onMovieSelected(MovieSelected event, Emitter<MovieDetailsState> emit) async {
try{
final movie = await _fetchMovieDetails(event.query);
return emit(state.copyWith(
status: MovieDetailsStatus.success,
movie: movie,
));
} catch (_) {
emit(state.copyWith(status: MovieDetailsStatus.failure));
}
}
Future<MovieDetails> _fetchMovieDetails(String id) async {
final movie = apiService.fetchMovieDetails(id);
return movie;
}
String shouldIWatchIt() {
final movie = state.movie;
if(movie.revenue - movie.budget > 1000000 && DateTime.now().weekday == DateTime.sunday){
return 'Yes';
} else {
return 'No';
}
}
}
MovieDetailsBloc movieDetailsBloc = MovieDetailsBloc();
and you can access it anywhere in your code with movieDetailsBloc.add or whatever you want.
I am trying to add a search function in my flutter app, the search bar is showing and there's not errors but its not working and it doesn't return any results.
the data list is from an API that I already called using the rest API
// ignore_for_file: use_key_in_widget_constructors, avoid_print, avoid_unnecessary_containers, curly_braces_in_flow_control_structures, prefer_const_constructors, non_constant_identifier_names, unnecessary_new, avoid_function_literals_in_foreach_calls, unused_import, avoid_types_as_parameter_names, unused_label
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:myapp2/Service_Request/SR.dart';
import 'package:myapp2/main.dart';
import 'package:myapp2/Service_Request/second.dart';
import '../Classes/demandes.dart';
import 'SR_details.dart';
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DataFromAPI(),
);
}
}
class DataFromAPI extends StatefulWidget {
#override
_DataFromAPIState createState() => _DataFromAPIState();
}
List<Attributes> _MyAllData = [];
var _srAttributes = [];
class _DataFromAPIState extends State<DataFromAPI> {
#override
void initState() {
loadData().then((value) {
setState(() {
_srAttributes.addAll(value);
});
});
super.initState();
}
Future<List<Sr>> loadData() async {
try {
var response = await http.get(Uri.parse(
'http://192.168.1.30:9080/maxrest/rest/mbo/sr/?_lid=azizl&_lpwd=max12345m&_format=json'));
if (response.statusCode == 200) {
final jsonBody = json.decode(response.body);
Demandes data = Demandes.fromJson(jsonBody);
final srAttributes = data.srMboSet.sr;
return srAttributes;
}
} catch (e) {
throw Exception(e.toString());
}
throw Exception("");
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text('Liste des Demandes'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () => Navigator.push(
context, MaterialPageRoute(builder: (context) => SR()))),
),
body: FutureBuilder<List<Sr>?>(
future: loadData(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
return new ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: ((_, index) {
return index == 0
? _searchbar()
: new ListTile(
title: new Card(
margin: new EdgeInsets.symmetric(
vertical: 2.0, horizontal: 8.0),
elevation: 10,
child: new ListTile(
title: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(padding: new EdgeInsets.all(2.0)),
new Text(
'Ticket ID : ${snapshot.data![index].attributes.ticketid.content}'),
new Text(
'status : ${snapshot.data![index].attributes.status.content}'),
new Text(
'description : ${snapshot.data![index].attributes.description?.content}'),
new Text(
'Reported by : ${snapshot.data![index].attributes.reportedby.content}'),
new Text(
'Reoprt date : ${snapshot.data![index].attributes.statusdate.content}'),
],
),
trailing: Icon(Icons.arrow_forward_ios_rounded),
),
),
onTap: () {
Navigator.of(context)
.push(
new MaterialPageRoute(
builder: (BuildContext context) =>
new SrDetailsScreen(
sr: snapshot.data![index]),
),
)
.then((data) {});
});
}),
);
}
},
),
),
);
}
_searchbar() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Search ..."),
onChanged: (text) {
text = text.toLowerCase();
setState(() {
_srAttributes = _MyAllData.where((srAttributes) {
var idticket = srAttributes.description!.content.toLowerCase();
return idticket.contains(text);
}).toList();
});
},
),
);
}
}
FutureBuilder loads values of current future. You are assigning a function result to FutureBuilder so its value always changes dynamically.
Create variable to keep Future's value.
Future<List<Sr>>? dataToLoad;
Whenever you want to load data from server ( for example, on text changed ):
setState((){
dataToLoad = loadData();
});
And use it in FutureBuilder:
FutureBuilder<List<Sr>?>(
future: dataToLoad,
I am working on a app were I get data from the ESP32 and display it on a simple page. Here is my code for my sensorpage:
import 'dart:async';
import 'dart:convert' show utf8;
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
class sensorpage extends StatefulWidget {
const sensorpage({Key? key, required this.device}) : super(key: key);
final BluetoothDevice device;
#override
_sensorpageState createState() => _sensorpageState();
}
class _sensorpageState extends State<sensorpage> {
final String SERVICE_UUID = "edb91e04-3e19-11ec-9bbc-0242ac130002";
final String CHARACTERISTIC_UUID = "edb920c0-3e19-11ec-9bbc-0242ac130002";
late bool isReady;
//String val1 = "";
//int pot1 = 0;
FlutterBlue flutterBlue = FlutterBlue.instance;
//late StreamSubscription<ScanResult> scanSubScription;
//late BluetoothDevice targetDevice;
late Stream<List<int>> stream;
#override
void initState() {
super.initState();
isReady = false;
connectToDevice();
}
connectToDevice() async {
if (widget.device == null) {
_Pop();
return;
}
Timer(const Duration(seconds: 15), () {
if (!isReady) {
disconnectFromDevice();
_Pop();
}
});
await widget.device.connect();
discoverServices();
}
disconnectFromDevice() {
if (widget.device == null) {
_Pop();
return;
}
widget.device.disconnect();
}
discoverServices() async {
if (widget.device == null) {
_Pop();
return;
}
List<BluetoothService> services = await widget.device.discoverServices();
services.forEach((service) {
if (service.uuid.toString() == SERVICE_UUID) {
service.characteristics.forEach((characteristic) {
if (characteristic.uuid.toString() == CHARACTERISTIC_UUID) {
characteristic.setNotifyValue(!characteristic.isNotifying);
stream = characteristic.value;
setState(() {
isReady = true;
});
}
});
}
});
if (!isReady) {
_Pop();
}
}
Future<bool> _onWillPop() async {
bool shouldPop = false;
await showDialog(
context: context,
builder: (context) =>
AlertDialog(
title: const Text('Are you sure?'),
content: const Text('Do you want to disconnect device and go back?'),
actions: <Widget>[
ElevatedButton(
onPressed: () {
// shouldPop is already false
},
child: const Text('No')),
ElevatedButton(
onPressed: () async {
await disconnectFromDevice();
Navigator.of(context).pop();
shouldPop = true;
},
child: const Text('Yes')),
],
));
return shouldPop;
}
_Pop() {
Navigator.of(context).pop(true);
}
String _dataParser( List<int> dataFromDevice) {
return utf8.decode(dataFromDevice);
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
appBar: AppBar(
title: const Text('Test'),
),
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError){
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.active) {
var currentValue = _dataParser (snapshot.data!);
//val1 = currentValue.split(',')[0];
//pot1 = int.parse(val1);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Current value',
style: TextStyle(fontSize: 14)),
Text('${currentValue} jawool',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24))
])
);
} else {
return const Text('Check the stream');
}
},
)),
)
));
}
}´
My Problem is that my second container where I display my data is shown as unnecessary but I don´t know why.
I assume you mean this piece of code?
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: Container(
child: StreamBuilder<List<int>>(
If isReady is true you return Container(child: Container(child: SteamBuilder));
You should change it to this and it should be fine:
body: Container(
child: !isReady
? const Center(
child: Text(
"Waiting...",
style: TextStyle(fontSize: 24, color: Colors.red),
),
)
: StreamBuilder<List<int>>(
The first Container is just wrapping the content based on the boolean and you don't need it. According to the flutter team:
Wrapping a widget in Container with no other parameters set has no effect and makes code needlessly more complex
So instead you can directly do:
body: !isReady ? buildSomething() : Container(....more code);
I fetch multiple images from the gallery and display them to the user. Now the user can fetch an unlimited number of images. I need to make a restriction or limit on the number of images that the user can import and choose, for example, only four images, and no more image can be inserted. How can do that?
I am using the following library: image_picker
// Pick multiple images
final List<XFile>? images = await _picker.pickMultiImage();
Full code:
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Picker Demo',
home: MyHomePage(title: 'Image Picker Example'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<XFile> _imageFileList;
set _imageFile(XFile value) {
_imageFileList = value == null ? null : [value];
}
dynamic _pickImageError;
bool isVideo = false;
final ImagePicker _picker = ImagePicker();
void _onImageButtonPressed(ImageSource source,
{BuildContext context, bool isMultiImage = false}) async {
if (isMultiImage) {
try {
final pickedFileList = await _picker.pickMultiImage(
maxWidth: 66,
maxHeight: 66,
imageQuality: 66,
);
setState(() {
_imageFileList = pickedFileList;
});
} catch (e) {
setState(() {
_pickImageError = e;
});
}
}
}
Widget _previewImages() {
if (_imageFileList != null) {
return Semantics(
child: ListView.builder(
key: UniqueKey(),
itemBuilder: (context, index) {
return Semantics(
label: 'image_picker_example_picked_image',
child: kIsWeb
? Image.network(_imageFileList[index].path)
: Image.file(File(_imageFileList[index].path)),
);
},
itemCount: _imageFileList.length,
),
label: 'image_picker_example_picked_images');
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await _picker.retrieveLostData();
if (response.isEmpty) {
return;
}
if (response.file != null) {
if (response.type == RetrieveType.video) {
isVideo = true;
} else {
isVideo = false;
setState(() {
_imageFile = response.file;
_imageFileList = response.files;
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android
? FutureBuilder<void>(
future: retrieveLostData(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
case ConnectionState.done:
return _previewImages();
default:
if (snapshot.hasError) {
return Text(
'Pick image/video error: ${snapshot.error}}',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
},
)
: _previewImages(),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: FloatingActionButton(
onPressed: () {
isVideo = false;
_onImageButtonPressed(
ImageSource.gallery,
context: context,
isMultiImage: true,
);
},
heroTag: 'image1',
tooltip: 'Pick Multiple Image from gallery',
child: const Icon(Icons.photo_library),
),
),
],
),
);
}
}
set the List that holds the images which is in your case _imageFileList to hold not more than the number of images you need. You can change the method _previewImages to
Widget _previewImages() {
if (_imageFileList != null && !_imageFileList.length>4 ) {
return Semantics(
child: ListView.builder(
key: UniqueKey(),
itemBuilder: (context, index) {
return Semantics(
label: 'image_picker_example_picked_image',
child: kIsWeb
? Image.network(_imageFileList[index].path)
: Image.file(File(_imageFileList[index].path)),
);
},
itemCount: _imageFileList.length,
),
label: 'image_picker_example_picked_images');
} else if (_pickImageError != null) {
return Text(
'Pick image error: $_pickImageError',
textAlign: TextAlign.center,
);
} else {
return const Text(
'You have not yet picked an image.',
textAlign: TextAlign.center,
);
}
}
I am not sure if this is possible, but with SwiftUI I have a mediaplayer class which has all my media player controls in it.
I am wondering if it is possible to have a flutter class file that hold flutter_radio_player and 1 media player that can change audio source?
The issue I have ran into with our old android app is we can't change the track without it creating a whole new media player.
I can't find any sample code on how to do this.
My code currently:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:flutter_radio_player/flutter_radio_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
var playerState = FlutterRadioPlayer.flutter_radio_paused;
var volume = 0.8;
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
int _currentIndex = 0;
final List<Widget> _children = [
new MyApp(),
];
FlutterRadioPlayer _flutterRadioPlayer = new FlutterRadioPlayer();
#override
void initState() {
super.initState();
initRadioService();
}
Future<void> initRadioService() async {
try {
await _flutterRadioPlayer.init(
"DRN1", "Live", "http://stream.radiomedia.com.au:8003/stream", "false");
} on PlatformException {
print("Exception occurred while trying to register the services.");
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Radio Player Example'),
),
body: Center(
child: Column(
children: <Widget>[
StreamBuilder(
stream: _flutterRadioPlayer.isPlayingStream,
initialData: widget.playerState,
builder:
(BuildContext context, AsyncSnapshot<String> snapshot) {
String returnData = snapshot.data;
print("object data: " + returnData);
switch (returnData) {
case FlutterRadioPlayer.flutter_radio_stopped:
return RaisedButton(
child: Text("Start listening now"),
onPressed: () async {
await initRadioService();
});
break;
case FlutterRadioPlayer.flutter_radio_loading:
return Text("Loading stream...");
case FlutterRadioPlayer.flutter_radio_error:
return RaisedButton(
child: Text("Retry ?"),
onPressed: () async {
await initRadioService();
});
break;
default:
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () async {
print("button press data: " +
snapshot.data.toString());
await _flutterRadioPlayer.playOrPause();
},
icon: snapshot.data ==
FlutterRadioPlayer
.flutter_radio_playing
? Icon(Icons.pause)
: Icon(Icons.play_arrow)),
IconButton(
onPressed: () async {
await _flutterRadioPlayer.stop();
},
icon: Icon(Icons.stop))
]);
break;
}
}),
Slider(
value: widget.volume,
min: 0,
max: 1.0,
onChanged: (value) => setState(() {
widget.volume = value;
_flutterRadioPlayer.setVolume(widget.volume);
})),
Text("Volume: " + (widget.volume * 100).toStringAsFixed(0))
],
),
),
),
);
}
}
FlutterRadioPlayer Author here. With the new release of the player, you can do this.
You just have to call
_flutterRadioPlayer.setUrl('URL_HERE')
The player will automatically set the old stream to a halt and start the new stream. Yes, you can set it to autoplay when ready as well. Just refer to the docs in new release.