Skip to content

Commit

Permalink
Add continuous recording tap
Browse files Browse the repository at this point in the history
  • Loading branch information
maxkrieger committed Dec 28, 2021
1 parent a1d5b69 commit 1b32a03
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 22 deletions.
2 changes: 2 additions & 0 deletions lib/consts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ const lastRouteKey = "last_route";
const lastOutlineKey = "last_outline";

const classicPurple = Color.fromRGBO(169, 129, 234, 1.0);
const basePurple = Color.fromRGBO(163, 95, 255, 1);
const warmRed = Color.fromRGBO(241, 52, 125, 1.0);
final locationInstance = Location();
const defaultEmoji = "🔮";
3 changes: 1 addition & 2 deletions lib/state/notes_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,7 @@ class NotesModel extends ChangeNotifier {
Future<void> stopRecording(int color) async {
Sentry.addBreadcrumb(
Breadcrumb(message: "Stop recording", timestamp: DateTime.now()));
// This delay prevents cutoff
await Future.delayed(const Duration(milliseconds: 300));

final note = currentlyPlayingOrRecording;
currentlyPlayingOrRecording = null;
notifyListeners();
Expand Down
16 changes: 13 additions & 3 deletions lib/state/player_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ enum PlayerState {
ready,
playing,
recording,
// processing
recordingContinuously
}

Future<Directory> getRecordingsDir() async {
Expand Down Expand Up @@ -75,15 +75,25 @@ class PlayerModel extends ChangeNotifier {
toFile: getPathFromFilename(note.filePath!),
sampleRate: 44100,
bitRate: 128000);
playerState = PlayerState.recording;
// If not already flagged as continuous
if (playerState != PlayerState.recordingContinuously) {
playerState = PlayerState.recording;
}
notifyListeners();
}
}

void setContinuousRecording() async {
playerState = PlayerState.recordingContinuously;
notifyListeners();
}

Future<Duration?> stopRecording({Note? note}) async {
await _recorder.stopRecorder();
playerState = PlayerState.ready;
notifyListeners();
// This delay prevents cutoff
await Future.delayed(const Duration(milliseconds: 300));
await _recorder.stopRecorder();
if (note == null) {
return null;
}
Expand Down
4 changes: 2 additions & 2 deletions lib/widgets/note_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class NoteItem extends StatefulWidget {
}

Color computeColor(int? magnitude) {
Color a = const Color.fromRGBO(163, 95, 255, 1);
Color b = const Color.fromRGBO(241, 52, 125, 1.0);
Color a = basePurple;
Color b = warmRed;
double t = magnitude != null && magnitude <= 100 ? magnitude / 100 : 0;
return Color.lerp(a, b, t)!;
}
Expand Down
52 changes: 38 additions & 14 deletions lib/widgets/record_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class RecordButton extends StatefulWidget {

class _RecordButtonState extends State<RecordButton> {
Offset offset = const Offset(0, 0);
final Stopwatch _stopwatch = Stopwatch();

Color computeShadowColor(double dy) {
Color a = const Color.fromRGBO(169, 129, 234, 0.6);
Expand All @@ -26,17 +27,25 @@ class _RecordButtonState extends State<RecordButton> {
}

_stopRecord(_) async {
int magnitude = max(
((-1 * offset.dy / MediaQuery.of(context).size.height) * 100).toInt(),
0);
await context.read<NotesModel>().stopRecording(magnitude);
if (_stopwatch.elapsedMilliseconds > 200) {
_stopwatch.stop();
_stopwatch.reset();
int magnitude = max(
((-1 * offset.dy / MediaQuery.of(context).size.height) * 100).toInt(),
0);
await context.read<NotesModel>().stopRecording(magnitude);
} else {
// If finger lifted in time, this was a tap not a hold. Keep recording
context.read<PlayerModel>().setContinuousRecording();
}
}

_stopRecord0() {
_stopRecord(null);
}

_startRecord(_) async {
_stopwatch.start();
await context.read<NotesModel>().startRecording();
}

Expand All @@ -51,7 +60,6 @@ class _RecordButtonState extends State<RecordButton> {
Widget build(BuildContext context) {
final playerState =
context.select<PlayerModel, PlayerState>((p) => p.playerState);
final isRecording = playerState == PlayerState.recording;
return GestureDetector(
onTapDown: _startRecord,
onTapUp: _stopRecord,
Expand All @@ -70,7 +78,11 @@ class _RecordButtonState extends State<RecordButton> {
},
child: AnimatedOpacity(
duration: const Duration(milliseconds: 100),
opacity: playerState == PlayerState.ready || isRecording ? 1.0 : 0.0,
opacity: playerState == PlayerState.ready ||
playerState == PlayerState.recording ||
playerState == PlayerState.recordingContinuously
? 1.0
: 0.0,
child: AnimatedContainer(
width: 200,
height: 75,
Expand All @@ -80,34 +92,46 @@ class _RecordButtonState extends State<RecordButton> {
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (!isRecording) ...[
const Icon(Icons.mic, color: Colors.white),
if (playerState != PlayerState.recording) ...[
Icon(
playerState == PlayerState.recordingContinuously
? Icons.stop
: Icons.mic,
color: Colors.white),
const SizedBox(
width: 10.0,
)
],
Text(
isRecording ? "recording" : "hold to record",
playerState == PlayerState.recordingContinuously
? "tap to stop"
: playerState == PlayerState.recording
? "recording"
: "hold to record",
style:
const TextStyle(color: Colors.white, fontSize: 15.0),
)
])),
decoration: BoxDecoration(
boxShadow: [
const BoxShadow(
color: Color.fromRGBO(156, 103, 241, .36),
BoxShadow(
color: playerState == PlayerState.recordingContinuously
? warmRed.withOpacity(0.5)
: const Color.fromRGBO(156, 103, 241, .36),
blurRadius: 18.0,
spreadRadius: 0.0,
offset: Offset(0, 7)),
if (isRecording)
offset: const Offset(0, 7)),
if (playerState == PlayerState.recording)
BoxShadow(
color: computeShadowColor(offset.dy),
blurRadius: 120.0,
spreadRadius: 120.0,
offset: offset + const Offset(-100, -95))
],
borderRadius: BorderRadius.circular(100.0),
color: classicPurple.withOpacity(0.9),
color: playerState == PlayerState.recordingContinuously
? warmRed
: classicPurple,
)),
));
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.17.2+74
version: 1.18.0+75

environment:
sdk: ">=2.12.0 <3.0.0"
Expand Down

0 comments on commit 1b32a03

Please sign in to comment.