feat: audio styling

This commit is contained in:
Jacques Doeleman 2022-10-27 11:21:24 +02:00
parent 64fc57a8b9
commit 660549fcf6
2 changed files with 179 additions and 106 deletions

View file

@ -8,4 +8,8 @@
## 0.0.3 ## 0.0.3
- Fixed bug where onTap was not working when header is set - Fixed bug where onTap was not working when header is set
## 0.1.0
- Ability to set styling for the audio input.

View file

@ -15,10 +15,13 @@ class MediaPickerInputAudio implements MediaPickerInput {
this.checkPageSettings, this.checkPageSettings,
this.onComplete, this.onComplete,
required this.audioService, required this.audioService,
this.inputStyling,
}); });
final AudioService audioService; final AudioService audioService;
final AudioInputStyling? inputStyling;
@override @override
String label; String label;
@ -38,6 +41,7 @@ class MediaPickerInputAudio implements MediaPickerInput {
throw Exception("No recording returned"); throw Exception("No recording returned");
} }
}, },
inputStyling: inputStyling ?? AudioInputStyling(),
), ),
), ),
); );
@ -66,12 +70,15 @@ class Recorder extends ConsumerStatefulWidget {
const Recorder({ const Recorder({
required this.onComplete, required this.onComplete,
required this.audioService, required this.audioService,
required this.inputStyling,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
final void Function(MediaResult value) onComplete; final void Function(MediaResult value) onComplete;
final AudioService audioService; final AudioService audioService;
final AudioInputStyling inputStyling;
@override @override
ConsumerState<Recorder> createState() => _RecorderState(); ConsumerState<Recorder> createState() => _RecorderState();
} }
@ -87,17 +94,18 @@ class _RecorderState extends ConsumerState<Recorder> {
return Scaffold( return Scaffold(
body: Stack( body: Stack(
children: [ children: [
Container( widget.inputStyling.background ??
decoration: const BoxDecoration( Container(
gradient: RadialGradient( decoration: const BoxDecoration(
radius: 2, gradient: RadialGradient(
colors: [ radius: 2,
Color(0xFFFFFFFF), colors: [
Color(0xFFCCCCCC), Color(0xFFFFFFFF),
], Color(0xFFCCCCCC),
],
),
),
), ),
),
),
Center( Center(
child: FutureBuilder<String>( child: FutureBuilder<String>(
future: widget.audioService.setWorkingDirectory(), future: widget.audioService.setWorkingDirectory(),
@ -107,9 +115,8 @@ class _RecorderState extends ConsumerState<Recorder> {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
const Spacer( if (widget.inputStyling.pageContent != null)
flex: 5, widget.inputStyling.pageContent!,
),
StreamBuilder( StreamBuilder(
stream: Stream.periodic( stream: Stream.periodic(
recording recording
@ -123,7 +130,8 @@ class _RecorderState extends ConsumerState<Recorder> {
clock.getCurrentTime(), 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<Recorder> {
Row( Row(
children: [ children: [
const Spacer(), const Spacer(),
SizedBox( widget.inputStyling.playButton?.call(
width: 82, recording,
height: 82, playOnTap,
child: Stack( ) ??
children: [ SizedBox(
Center( width: 82,
child: Container( height: 82,
decoration: BoxDecoration( child: Stack(
borderRadius: BorderRadius.circular(45), children: [
gradient: const LinearGradient( Center(
colors: [
Color(0xFFF0F0F0),
Color(0xFFC6C6C6),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Center(
child: Container( child: Container(
width: 60,
height: 60,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: borderRadius:
BorderRadius.circular(45), BorderRadius.circular(45),
gradient: const LinearGradient( gradient: const LinearGradient(
colors: [ colors: [
Color(0xFFC6C6C6),
Color(0xFFF0F0F0), Color(0xFFF0F0F0),
Color(0xFFC6C6C6),
], ],
begin: Alignment.topLeft, begin: Alignment.topLeft,
end: Alignment.bottomRight, 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( const Spacer(
@ -257,6 +257,75 @@ class _RecorderState extends ConsumerState<Recorder> {
), ),
); );
} }
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. /// Generic clock class can be created and used to keep the time.