How to create Custom camera with Countdown Timer in Flutter.
I have tried take container under stack on camera but this Container is not showing on camera.
Here I am focus only functionality check below code may this is help full for you.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:camera/camera.dart';
import 'dart:async';
import 'dart:io';
List<CameraDescription> cameras = <CameraDescription>[];
Future<void> main() async {
// Fetch the available cameras before initializing the app.
try {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
} on CameraException catch (e) {
print("${e.code} ${e.description}");
}
runApp(CameraApp());
}
class CameraApp extends StatefulWidget {
#override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
CameraController? controller;
Timer? countdownTimer;
Duration myDuration = const Duration(seconds: 10);
#override
void initState() {
super.initState();
controller = CameraController(cameras[0], ResolutionPreset.max);
controller?.initialize().then((_) {
if (!mounted) {
return;
}
setState(() {});
});
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
void startTimer() {
countdownTimer =
Timer.periodic(const Duration(seconds: 1), (_) => setCountDown());
}
void setCountDown() {
const reduceSecondsBy = 1;
setState(() {
final seconds = myDuration.inSeconds - reduceSecondsBy;
if (seconds < 0) {
countdownTimer!.cancel();
} else {
myDuration = Duration(seconds: seconds);
}
});
}
#override
Widget build(BuildContext context) {
if (!controller!.value.isInitialized) {
return Container();
}
String strDigits(int n) => n.toString().padLeft(2, '0');
final days = strDigits(myDuration.inDays);
// Step 7
final hours = strDigits(myDuration.inHours.remainder(24));
final minutes = strDigits(myDuration.inMinutes.remainder(60));
final seconds = strDigits(myDuration.inSeconds.remainder(60));
return MaterialApp(
home: Scaffold(
body: Center(
child: Stack(
alignment: Alignment.center,
children: [
CameraPreview(controller!),
Text(
'$minutes:$seconds',
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 30),
),
Padding(
padding: const EdgeInsets.only(top: 100),
child: ElevatedButton(
onPressed: startTimer, child: const Text("Start")),
)
],
),
),
),
);
}
}
Related
I'm new to flutter and very new to riverpod. I've just been helped with some code to use a countdown clock that can then be viewed on multiple pages using Riverpod.
here is the Riverpod State Notifier.
final countDownControllerProvider = StateNotifierProvider.family
.autoDispose<CountdownController, Duration, Duration>(
(ref, initialDuration) {
return CountdownController(initialDuration);
});
class CountdownController extends StateNotifier<Duration> {
Timer? timer;
final Duration initialDuration;
CountdownController(this.initialDuration) : super(initialDuration) {
stopTimer();
}
void startTimer() {
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (state == Duration.zero) {
timer.cancel();
} else {
if (mounted) {
state = state - const Duration(seconds: 1);
} else {
timer.cancel();
}
}
});
}
}
Currently, the input for the time to display on the countdown clock is inputted when you call CountdownController. (the class with startTimer function inside it).
the problem I'm having is if I want to call startTimer(), I need to reinput the time to display which is a problem if I'm stopping and starting the clock.
how would I move the time input from a parameter of the CountdownController class, into a function inside the class that I can then call on when needed so I don't have to set it when starting/stopping the clock?
and what would that code look like?
thanks so much
I didn't test it. If you need to save duration to state, consider making the state a data class.
EDIT: tested.
import 'dart:math';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
import 'dart:async';
void main() {
runApp(const ProviderScope(child: App()));
}
final countDownControllerProvider =
StateNotifierProvider.autoDispose<CountdownController, Timer?>((ref) {
return CountdownController(ref);
});
final counterProvider = StateProvider((_) => 0);
final intervalProvider = StateProvider((_) => Duration(seconds: 1));
class CountdownController extends StateNotifier<Timer?> {
CountdownController(this.ref) : super(null);
final Ref ref;
void startTimer() {
state?.cancel();
state = Timer.periodic(ref.read(intervalProvider), (timer) {
ref.read(counterProvider.notifier).state++;
});
}
void stopTimer() {
state?.cancel();
}
void accelerate(double multiplier) {
final duration = ref.read(intervalProvider);
ref.read(intervalProvider.notifier).state = Duration(
milliseconds: (duration.inMilliseconds * (1 / multiplier)).floor(),
);
startTimer();
}
void speedUp() {
accelerate(sqrt2);
}
void speedDown() {
accelerate(1 / sqrt2);
}
}
class App extends ConsumerWidget {
const App();
#override
Widget build(BuildContext context, WidgetRef ref) {
final counter = ref.watch(counterProvider);
final controller = ref.watch(countDownControllerProvider.notifier);
final timer = ref.watch(countDownControllerProvider);
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Text("$counter", style: Theme.of(context).textTheme.headlineLarge),
SizedBox(height: 24),
Row(children: [
SizedBox(width: 24),
Expanded(
child: ElevatedButton(
onPressed: controller.startTimer,
child: Text(timer == null ? "start" : "stop"),
),
),
SizedBox(width: 24),
Expanded(
child: ElevatedButton(
onPressed: controller.speedUp,
child: Text("+"),
),
),
SizedBox(width: 24),
Expanded(
child: ElevatedButton(
onPressed: controller.speedDown,
child: Text("-"),
),
),
SizedBox(width: 24),
]),
]),
),
),
);
}
}
I wrote a code like this:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_sms_inbox/flutter_sms_inbox.dart';
class Inbox extends StatefulWidget {
const Inbox({Key? key}) : super(key: key);
#override
State<Inbox> createState() => _InboxState();
}
SmsQuery query = new SmsQuery();
List<SmsMessage> AllMessages = [];
Timer? _timer;
class _InboxState extends State<Inbox> {
#override
void initState() {
GetAllMessages();
_timer = Timer.periodic(const Duration(seconds: 1), (Timer t) {
GetAllMessages();
print("refreshed");
print(AllMessages); // output: []
});
super.initState();
}
Future<void> GetAllMessages() async {
Future.delayed(Duration.zero, () async {
List<SmsMessage> messages = await query.querySms(
kinds: [SmsQueryKind.inbox],
count: 50,
);
setState(() {
AllMessages = messages;
});
});
}
#override
void dispose() {
_timer?.cancel();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Page(),
),
);
}
}
Widget Page() {
if (AllMessages == null) {
return Text("No message");
} else {
Column(
children: [
const SizedBox(height: 25),
Container(
child: Column(
children: AllMessages.map((msg) {
return Container(
child: Card(
child: ListTile(
leading: Text("${msg.body}"),
title: Text("${msg.address}"),
),
),
);
}
).toList(),
),
),
],
);
}
return SizedBox();
}
I'm trying to access and list SMS's on the phone. I save the SMS in the list called AllMessages. If there is no SMS, I want it to show a Text named No message but it doesn't.
It shows blank as in the picture:
Why could this be? How can I solve the problem? Thanks in advance for your help.
I am trying to get the user to press a record button, to then speak. His memo is recorded and then when the user tap on the Text widget displaying the name of the audio file, the file should be read so he can listen again to what he has recorded.
When I try, I am getting connection lost and the simulator crash. I do not find what is the problem in my code. I guess it is because I am still new with Flutter. Your help is welcome as I am stuck with this for several days. Many thanks.
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_audio_recorder2/flutter_audio_recorder2.dart';
import 'package:path_provider/path_provider.dart';
enum RecordingState {
UnSet,
Set,
Recording,
Stopped,
}
void main66() => runApp(MyTest());
bool isRecording = false;
class MyTest extends StatelessWidget {
const MyTest({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
// backgroundColor: Colors.white,
body: HomeViewRecorder(),//HomeViewRecorder(),
),
);
}
}
class HomeViewRecorder extends StatefulWidget {
final String _title;
const HomeViewRecorder({Key key, String title}) : _title = title,
super(key: key);
#override
_HomeViewRecorderState createState() => _HomeViewRecorderState();
}
class _HomeViewRecorderState extends State<HomeViewRecorder> {
Directory appDirectory;
String records = '';
#override
void initState() {
super.initState();
getApplicationDocumentsDirectory().then((value) {
appDirectory = (value);
setState(() {
print(appDirectory);
});
});
}
void dispose() {
appDirectory.delete();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold (
appBar: AppBar(
title: Text('My recorder Test')),
body: Column(
children: [
Expanded(child:
InkWell(child: RecordListView(records:records)),
),
Center(child: Record_Widget(
onSaved:
_onRecordComplete)),
]
)
);
}
_onRecordComplete() {
records ='';
appDirectory.list().listen((onData) {
if (onData.path.contains('.aac')) records=(onData.path);
}).onDone(() {
setState(() {});
});
}
}
class RecordListView extends StatefulWidget {
final String records;
const RecordListView({
Key key,
this.records,
}) : super(key: key);
#override
_RecordListViewState createState() => _RecordListViewState();
}
class _RecordListViewState extends State<RecordListView> {
int _totalDuration;
int _currentDuration;
double _completedPercentage = 0.0;
bool _isPlaying = false;
int _selectedIndex = -1;
#override
Widget build(BuildContext context){
return Column(
children: [
widget.records.isEmpty?
Text('No records yet'): InkWell(child: Text(widget.records.split("/").last+DateTime.now().toString()),
onTap: _onPlay,),
],
);
}
Future<void> _onPlay({ String filePath, int index}) async {
AudioPlayer audioPlayer = AudioPlayer();
if (!_isPlaying) {
audioPlayer.play(filePath, isLocal: true);
setState(() {
_selectedIndex = index;
_completedPercentage = 0.0;
_isPlaying = true;
});
audioPlayer.onPlayerCompletion.listen((_) {
setState(() {
_isPlaying = false;
_completedPercentage = 0.0;
});
});
audioPlayer.onDurationChanged.listen((duration) {
setState(() {
_totalDuration = duration.inMicroseconds;
});
});
audioPlayer.onAudioPositionChanged.listen((duration) {
setState(() {
_currentDuration = duration.inMicroseconds;
_completedPercentage =
_currentDuration.toDouble() / _totalDuration.toDouble();
});
});
}
}
String _getDateFromFilePath({ String filePath}) {
String fromEpoch = filePath.substring(
filePath.lastIndexOf('/') + 1, filePath.lastIndexOf('.'));
DateTime recordedDate =
DateTime.fromMillisecondsSinceEpoch(int.parse(fromEpoch));
int year = recordedDate.year;
int month = recordedDate.month;
int day = recordedDate.day;
return ('$year-$month-$day');
}
}
class Record_Widget extends StatefulWidget {
final Function onSaved;
const Record_Widget({Key key,
this.onSaved,}) : super(key: key);
#override
_Record_WidgetState createState() => _Record_WidgetState();
}
class _Record_WidgetState extends State<Record_Widget> {
Directory appDirectory;
String records = '';
RecordingState _recordingState = RecordingState.UnSet;
// Recorder properties
FlutterAudioRecorder2 audioRecorder;
#override
void initState() {
super.initState();
FlutterAudioRecorder2.hasPermissions.then((hasPermission) {
if (hasPermission) {
_recordingState = RecordingState.Set;
}
});
}
#override
void dispose() {
_recordingState = RecordingState.UnSet;
super.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(100.0),
child: _RecordOrStopButton());
}
Container _RecordOrStopButton() {
return Container(
height: 90,
width: 90,
decoration: BoxDecoration(
border: Border.all(
width: 4.0,
color: Colors.grey,
),
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(4.0),
child: isRecording == false ?
_createRecordButton() : _createStopButton()),);
}
//Widget Button Record
Container _createRecordButton({IconData icon, Function onPressFunc}) {
return Container(child: ElevatedButton(
onPressed: () async {
await _onRecordButtonPressed();
setState(() {
_recordingState = RecordingState.Recording;
isRecording = true;
});
},
style: ButtonStyle(
shape: MaterialStateProperty.all(CircleBorder()),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor: MaterialStateProperty.all(
Colors.red), // <-- Button color
)));
}
//Widget Button Stop
Container _createStopButton() {
return Container(
padding: EdgeInsets.all(16),
width: 30.0,
height: 30.0,
child: ElevatedButton(
onPressed: () {
_onRecordButtonPressed();
setState(() {
isRecording = false;
});
},
style: ButtonStyle(
fixedSize: MaterialStateProperty.all(Size(10, 10)),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(color: Colors.red))),
padding: MaterialStateProperty.all(EdgeInsets.all(20)),
backgroundColor: MaterialStateProperty.all(Colors.red),
),
));
}
Future<void> _onRecordButtonPressed() async {
switch (_recordingState) {
case RecordingState.Set:
await _recordVoice();
break;
case RecordingState.Recording:
await _stopRecording();
_recordingState = RecordingState.Stopped;
break;
case RecordingState.Stopped:
await _recordVoice();
break;
case RecordingState.UnSet:
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Please allow recording from settings.'),
));
break;
}
}
_initRecorder() async {
Directory appDirectory = await getApplicationDocumentsDirectory();
String filePath = appDirectory.path +
'/' +
DateTime.now().millisecondsSinceEpoch.toString() +
'.aac';
audioRecorder =
FlutterAudioRecorder2(filePath, audioFormat: AudioFormat.AAC);
await audioRecorder.initialized;
}
_startRecording() async {
isRecording = true;
await audioRecorder.start();
await audioRecorder.current(channel: 0);
}
_stopRecording() async {
isRecording = false;
await audioRecorder.stop();
widget.onSaved();
}
Future<void> _recordVoice() async {
final hasPermission = await FlutterAudioRecorder2.hasPermissions;
if (hasPermission ?? false) {
await _initRecorder();
await _startRecording();
_recordingState = RecordingState.Recording;
} else {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Please allow recording from settings.'),
));
}
}
}
I am currently writing an app using Flutter and Dart. On a button onPressed event I would like to invoke an action that executes after timeLeft seconds unless it is cancelled by correctly entering a pin. Additionally, I would like to use the value timeLeft in a Text widget.
This would require a structure with the following functionality:
executing a function after an x amount of seconds
this function should execute unless some event (e.g. entering a pin correctly) has occurred.
the timeLeft value should be accessible to be used in a Text widget and should update as the timer progresses.
I am wondering how to do this according to flutter's and dart's best practices. For state management I am using the provider pattern so preferably this approach is compatible with the provider pattern.
This is what I have tried so far:
class Home extends ChangeNotifier {
int secondsLeft = 10;
void onPressedEmergencyButton(BuildContext context) {
countDown();
showDialog<void>(
context: context,
builder: (context) {
return ScreenLock(
title: Text(
"Sending message in ${context.read<Home>().secondsLeft} seconds"),
correctString: '1234',
canCancel: false,
didUnlocked: () {
Navigator.pop(context);
},
);
},
);
}
void countDown() {
Future.delayed(const Duration(seconds: 1), () {
secondsLeft =- 1;
notifyListeners();
if (secondsLeft <= 0) {
// Do something
return;
}
});
}
}
You can use CancelableOperation from async package.
Simplifying code-snippet and about _cancelTimer(bool) , this bool used to tell widget about true = time end, and on cancel false like _cancelTimer(false);, rest are described on code-comments.
class TS extends StatefulWidget {
const TS({Key? key}) : super(key: key);
#override
State<TS> createState() => _TSState();
}
class _TSState extends State<TS> {
Timer? _timer;
final Duration _refreseRate = const Duration(seconds: 1);
CancelableOperation? _cancelableOperation;
Duration taskDuration = const Duration(seconds: 5);
bool isSuccess = false;
_initTimer() {
if (_cancelableOperation != null) {
_cancelTimer(false);
}
_cancelableOperation = CancelableOperation.fromFuture(
Future.delayed(Duration.zero),
).then((p0) {
_timer = Timer.periodic(_refreseRate, (timer) {
setState(() {
taskDuration -= _refreseRate;
});
if (taskDuration <= Duration.zero) {
/// task complete on end of duration
_cancelTimer(true);
}
});
}, onCancel: () {
_timer?.cancel();
setState(() {});
});
}
_cancelTimer(bool eofT) {
// cancel and reset everything
_cancelableOperation?.cancel();
_timer?.cancel();
_timer = null;
taskDuration = const Duration(seconds: 5);
isSuccess = eofT;
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (isSuccess)
Container(
height: 100,
width: 100,
color: Colors.green,
),
if (_timer != null)
Text("${taskDuration.inSeconds}")
else
const Text("init Timer"),
],
),
),
floatingActionButton: Row(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
child: const Text("init"),
onPressed: () {
_initTimer();
},
),
FloatingActionButton(
child: const Text("Cancel"),
onPressed: () {
_cancelTimer(false);
},
),
],
),
);
}
}
You can use the Timer class to run a function after a set Duration. It doesn't give you the time remaining, but you can calculate it yourself.
Here is a quick implementation I put together:
import 'dart:async';
import 'package:flutter/material.dart';
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
home: const Scaffold(
body: Center(
child: Countdown(),
),
),
);
}
}
class Countdown extends StatefulWidget {
const Countdown({Key? key}) : super(key: key);
#override
_CountdownState createState() => _CountdownState();
}
class _CountdownState extends State<Countdown> {
bool active = false;
Timer? timer;
Timer? refresh;
Stopwatch stopwatch = Stopwatch();
Duration duration = const Duration(seconds: 5);
_CountdownState() {
// this is just so the time remaining text is updated
refresh = Timer.periodic(
const Duration(milliseconds: 100), (_) => setState(() {}));
}
void start() {
setState(() {
active = true;
timer = Timer(duration, () {
stop();
onCountdownComplete();
});
stopwatch
..reset()
..start();
});
}
void stop() {
setState(() {
active = false;
timer?.cancel();
stopwatch.stop();
});
}
void onCountdownComplete() {
showDialog(
context: context,
builder: (context) => const AlertDialog(
title: Text('Countdown was not stopped!'),
),
);
}
int secondsRemaining() {
return duration.inSeconds - stopwatch.elapsed.inSeconds;
}
#override
void dispose() {
timer?.cancel();
refresh?.cancel();
stopwatch.stop();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (active) Text(secondsRemaining().toString()),
if (active)
TextButton(onPressed: stop, child: const Text('Stop'))
else
TextButton(onPressed: start, child: const Text('Start')),
],
);
}
}
I wanted to Download a Image with its progress and message. I wanted to show it in a dialog. When ever I click Download Button the Image gets downloaded and the Container pops up, but it does not Show any value.
The below code uses Image_downloader package. Raised button downloads the image and display the Blank Container without any value;
import 'dart:async';
import 'dart:io';
import 'Download.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_downloader/image_downloader.dart';
void main() => runApp(HomePage());
class HomePage extends StatefulWidget {
#override
HomePageState createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
String message = "";
String path = "";
int _progress = 0;
#override
void initState() {
super.initState();
ImageDownloader.callback(onProgressUpdate: (String imageId, int progress) {
setState(() {
_progress = progress;
});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
onPressed: () {
_downloadImage(
"https://images.unsplash.com/photo-1503023345310-bd7c1de61c7d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80",
);
showDialog(
context: context,
builder: (_) => FunkyOverlay(progress: _progress, message: message,),
);
},
child: Text("default destination"),
),
],
),
),
),
);
}
Future<void> _downloadImage(String url,
{AndroidDestinationType destination, bool whenError = false}) async {
String fileName;
String path;
try {
String imageId;
if (whenError) {
imageId = await ImageDownloader.downloadImage(url).catchError((error) {
if (error is PlatformException) {
var path = "";
if (error.code == "404") {
print("Not Found Error.");
} else if (error.code == "unsupported_file") {
print("UnSupported FIle Error.");
path = error.details["unsupported_file_path"];
}
setState(() {
message = error.toString();
path = path;
});
}
print(error);
}).timeout(Duration(seconds: 10), onTimeout: () {
print("timeout");
});
} else {
if (destination == null) {
imageId = await ImageDownloader.downloadImage(url);
} else {
imageId = await ImageDownloader.downloadImage(
url,
destination: destination,
);
}
}
if (imageId == null) {
return;
}
fileName = await ImageDownloader.findName(imageId);
path = await ImageDownloader.findPath(imageId);
} on PlatformException catch (error) {
setState(() {
message = error.message;
});
return;
}
if (!mounted) return;
setState(() {
message = 'Image Downloaded';
});
}
}
This is the Pop up Container Part
import 'package:flutter/material.dart';
class FunkyOverlay extends StatefulWidget {
String message;
int progress;
FunkyOverlay({#required this.message, #required this.progress});
#override
State<StatefulWidget> createState() => FunkyOverlayState(message, progress);
}
class FunkyOverlayState extends State<FunkyOverlay>
with SingleTickerProviderStateMixin {
String message;
int progress;
FunkyOverlayState(this.message, this.progress);
AnimationController controller;
Animation<double> scaleAnimation;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 450));
scaleAnimation =
CurvedAnimation(parent: controller, curve: Curves.elasticInOut);
controller.addListener(() {
setState(() {});
});
controller.forward();
}
#override
Widget build(BuildContext context) {
return Center(
child: Material(
color: Colors.transparent,
child: ScaleTransition(
scale: scaleAnimation,
child: Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
child: Padding(
padding: const EdgeInsets.all(50.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Downloaded: $progress'),
Text(message)
],
),
),
),
),
),
);
}
}
You can copy paste run full code below
You can use StreamBuilder to receive progress from onProgressUpdate
class HomePageState extends State<HomePage> {
...
#override
void initState() {
super.initState();
_events = new StreamController<int>.broadcast();;
_events.add(0);
ImageDownloader.callback(onProgressUpdate: (String imageId, int progress) {
setState(() {
print("progress $progress");
_progress = progress;
_events.add(progress);
});
return StreamBuilder<int>(
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return Center(
...
children: <Widget>[
Text('Downloaded: ${snapshot.data.toString()}'),
Text(message)
working demo
full code
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:image_downloader/image_downloader.dart';
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
#override
HomePageState createState() => HomePageState();
}
StreamController<int> _events;
class HomePageState extends State<HomePage> {
String message = "";
String path = "";
int _progress = 0;
#override
void initState() {
super.initState();
_events = new StreamController<int>.broadcast();
;
_events.add(0);
ImageDownloader.callback(onProgressUpdate: (String imageId, int progress) {
setState(() {
print("progress $progress");
_progress = progress;
_events.add(progress);
if (progress == 100) {
Navigator.pop(context);
}
});
});
}
#override
void dispose() {
// TODO: implement dispose
_events.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
RaisedButton(
onPressed: () {
_events.add(0);
_downloadImage(
"https://images.unsplash.com/photo-1503023345310-bd7c1de61c7d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&w=1000&q=80",
);
showDialog(
context: context,
builder: (_) => FunkyOverlay(
progress: _progress,
message: message,
),
);
},
child: Text("default destination"),
),
],
),
),
);
}
Future<void> _downloadImage(String url,
{AndroidDestinationType destination, bool whenError = false}) async {
String fileName;
String path;
try {
String imageId;
if (whenError) {
imageId = await ImageDownloader.downloadImage(url).catchError((error) {
if (error is PlatformException) {
var path = "";
if (error.code == "404") {
print("Not Found Error.");
} else if (error.code == "unsupported_file") {
print("UnSupported FIle Error.");
path = error.details["unsupported_file_path"];
}
setState(() {
message = error.toString();
path = path;
});
}
print(error);
}).timeout(Duration(seconds: 10), onTimeout: () {
print("timeout");
});
} else {
if (destination == null) {
imageId = await ImageDownloader.downloadImage(url);
} else {
imageId = await ImageDownloader.downloadImage(
url,
destination: destination,
);
}
}
if (imageId == null) {
print("imageId is null");
return;
}
fileName = await ImageDownloader.findName(imageId);
path = await ImageDownloader.findPath(imageId);
} on PlatformException catch (error) {
setState(() {
message = error.message;
});
return;
}
if (!mounted) return;
setState(() {
message = 'Image Downloaded';
});
}
}
class FunkyOverlay extends StatefulWidget {
String message;
int progress;
FunkyOverlay({#required this.message, #required this.progress});
#override
State<StatefulWidget> createState() => FunkyOverlayState(message, progress);
}
class FunkyOverlayState extends State<FunkyOverlay>
with SingleTickerProviderStateMixin {
String message;
int progress;
FunkyOverlayState(this.message, this.progress);
AnimationController controller;
Animation<double> scaleAnimation;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 450));
scaleAnimation =
CurvedAnimation(parent: controller, curve: Curves.elasticInOut);
controller.addListener(() {
setState(() {});
});
controller.forward();
}
#override
Widget build(BuildContext context) {
print("StreamBuilder build");
return StreamBuilder<int>(
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
print("snapshot.data ${snapshot.data.toString()}");
return Center(
child: Material(
color: Colors.transparent,
child: ScaleTransition(
scale: scaleAnimation,
child: Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
child: Padding(
padding: const EdgeInsets.all(50.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Downloaded: ${snapshot.data.toString()}'),
Text(message)
],
),
),
),
),
),
);
});
}
}