From 660549fcf6fd8f79b0050d44c80487e575757294 Mon Sep 17 00:00:00 2001 From: Jacques Doeleman Date: Thu, 27 Oct 2022 11:21:24 +0200 Subject: [PATCH] feat: audio styling --- CHANGELOG.md | 6 +- lib/src/inputs/input_audio.dart | 279 ++++++++++++++++++++------------ 2 files changed, 179 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a29731e..4390d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,4 +8,8 @@ ## 0.0.3 -- Fixed bug where onTap was not working when header is set \ No newline at end of file +- Fixed bug where onTap was not working when header is set + +## 0.1.0 + +- Ability to set styling for the audio input. diff --git a/lib/src/inputs/input_audio.dart b/lib/src/inputs/input_audio.dart index da004e4..64fc08f 100644 --- a/lib/src/inputs/input_audio.dart +++ b/lib/src/inputs/input_audio.dart @@ -15,10 +15,13 @@ class MediaPickerInputAudio implements MediaPickerInput { this.checkPageSettings, this.onComplete, required this.audioService, + this.inputStyling, }); final AudioService audioService; + final AudioInputStyling? inputStyling; + @override String label; @@ -38,6 +41,7 @@ class MediaPickerInputAudio implements MediaPickerInput { throw Exception("No recording returned"); } }, + inputStyling: inputStyling ?? AudioInputStyling(), ), ), ); @@ -66,12 +70,15 @@ class Recorder extends ConsumerStatefulWidget { const Recorder({ required this.onComplete, required this.audioService, + required this.inputStyling, Key? key, }) : super(key: key); final void Function(MediaResult value) onComplete; final AudioService audioService; + final AudioInputStyling inputStyling; + @override ConsumerState createState() => _RecorderState(); } @@ -87,17 +94,18 @@ class _RecorderState extends ConsumerState { return Scaffold( body: Stack( children: [ - Container( - decoration: const BoxDecoration( - gradient: RadialGradient( - radius: 2, - colors: [ - Color(0xFFFFFFFF), - Color(0xFFCCCCCC), - ], + widget.inputStyling.background ?? + Container( + decoration: const BoxDecoration( + gradient: RadialGradient( + radius: 2, + colors: [ + Color(0xFFFFFFFF), + Color(0xFFCCCCCC), + ], + ), + ), ), - ), - ), Center( child: FutureBuilder( future: widget.audioService.setWorkingDirectory(), @@ -107,9 +115,8 @@ class _RecorderState extends ConsumerState { return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - const Spacer( - flex: 5, - ), + if (widget.inputStyling.pageContent != null) + widget.inputStyling.pageContent!, StreamBuilder( stream: Stream.periodic( recording @@ -123,7 +130,8 @@ class _RecorderState extends ConsumerState { clock.getCurrentTime(), ), ), - style: Theme.of(context).textTheme.headline5, + style: widget.inputStyling.timeTextStyle ?? + Theme.of(context).textTheme.headline5, ); }, ), @@ -133,113 +141,105 @@ class _RecorderState extends ConsumerState { Row( children: [ const Spacer(), - SizedBox( - width: 82, - height: 82, - child: Stack( - children: [ - Center( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(45), - gradient: const LinearGradient( - colors: [ - Color(0xFFF0F0F0), - Color(0xFFC6C6C6), - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Center( + widget.inputStyling.playButton?.call( + recording, + playOnTap, + ) ?? + SizedBox( + width: 82, + height: 82, + child: Stack( + children: [ + Center( child: Container( - width: 60, - height: 60, decoration: BoxDecoration( borderRadius: BorderRadius.circular(45), gradient: const LinearGradient( colors: [ - Color(0xFFC6C6C6), Color(0xFFF0F0F0), + Color(0xFFC6C6C6), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), + child: Center( + child: Container( + width: 60, + height: 60, + decoration: BoxDecoration( + borderRadius: + BorderRadius.circular(45), + gradient: const LinearGradient( + colors: [ + Color(0xFFC6C6C6), + Color(0xFFF0F0F0), + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + ), + ), + ), + ), + Center( + child: IconButton( + iconSize: 65, + padding: EdgeInsets.zero, + splashRadius: 30, + onPressed: () { + playOnTap(); + }, + icon: Icon( + recording + ? Icons.pause + : Icons.play_arrow_rounded, + color: const Color(0xFF4C4C4C), + ), + ), + ) + ], + ), + ), + widget.inputStyling.nextButton != null + ? Expanded( + child: Center( + child: widget.inputStyling.nextButton!.call( + recording, + nextOnTap, + ), + ), + ) + : Expanded( + child: Center( + child: GestureDetector( + onTap: () async { + nextOnTap(); + }, + child: Container( + width: + MediaQuery.of(context).size.width * + 0.3, + height: 45, + decoration: BoxDecoration( + color: const Color(0xFFD8D8D8), + borderRadius: + BorderRadius.circular(15), + ), + child: Center( + child: Text( + 'Next', + style: Theme.of(context) + .textTheme + .button, + ), + ), ), ), ), ), - Center( - child: IconButton( - iconSize: 65, - padding: EdgeInsets.zero, - splashRadius: 30, - onPressed: () async { - if (recording) { - widget.audioService.recordStop(); - - clock.stopClock(); - - setState(() { - recording = false; - }); - } else { - widget.audioService.recordStart(); - - clock.startClock(); - - setState(() { - recording = true; - }); - } - }, - icon: Icon( - recording - ? Icons.pause - : Icons.play_arrow_rounded, - color: const Color(0xFF4C4C4C), - ), - ), - ) - ], - ), - ), - Expanded( - child: Center( - child: GestureDetector( - onTap: () async { - widget.audioService.recordStop(); - - widget.onComplete( - MediaResult( - fileValue: - await File(directory!).readAsBytes(), - ), - ); - - // ignore: use_build_context_synchronously - Navigator.pop(context); - }, - child: Container( - width: - MediaQuery.of(context).size.width * 0.3, - height: 45, - decoration: BoxDecoration( - color: const Color(0xFFD8D8D8), - borderRadius: BorderRadius.circular(15), - ), - child: Center( - child: Text( - 'Next', - style: Theme.of(context).textTheme.button, - ), - ), - ), - ), - ), - ), ], ), const Spacer( @@ -257,6 +257,75 @@ class _RecorderState extends ConsumerState { ), ); } + + playOnTap() { + if (recording) { + widget.audioService.recordStop(); + + clock.stopClock(); + + setState(() { + recording = false; + }); + } else { + widget.audioService.recordStart(); + + clock.startClock(); + + setState(() { + recording = true; + }); + } + } + + nextOnTap() async { + widget.audioService.recordStop(); + + widget.onComplete( + MediaResult( + fileValue: await File(directory!).readAsBytes(), + ), + ); + + // ignore: use_build_context_synchronously + Navigator.pop(context); + } +} + +/// Used by [MediaPickerInputAudio] to set styling options. +/// +/// background can be set to determine the background of the page. +/// +/// pageContent can be set to set any widget at the top of the page. +/// +/// timeTextStyle sets the [TextStyle] of the time that shows the recording duration. Defaults to headline5. +/// +/// playButton changes the default play/pause button. +/// +/// nextButton changes the default next/finish button. +class AudioInputStyling { + AudioInputStyling({ + this.background, + this.pageContent, + this.timeTextStyle, + this.playButton, + this.nextButton, + }); + + /// background can be set to determine the background of the page. + final Widget? background; + + /// pageContent can be set to set any widget at the top of the page. + final Widget? pageContent; + + /// timeTextStyle sets the [TextStyle] of the time that shows the recording duration. Defaults to headline5. + final TextStyle? timeTextStyle; + + /// playButton changes the default play/pause button. + final Widget Function(bool recording, Function onTap)? playButton; + + /// nextButton changes the default next/finish button. + final Widget Function(bool recording, Function onTap)? nextButton; } /// Generic clock class can be created and used to keep the time.