125 lines
3.3 KiB
Dart
125 lines
3.3 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:audioplayers/audioplayers.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:vibration/vibration.dart';
|
|
|
|
class FeedbackService {
|
|
FeedbackService() {
|
|
_configurePlayers();
|
|
}
|
|
|
|
final AudioPlayer _scanPlayer = AudioPlayer();
|
|
final AudioPlayer _successPlayer = AudioPlayer();
|
|
final AudioPlayer _warningPlayer = AudioPlayer();
|
|
|
|
static final AudioContext _loudContext = AudioContext(
|
|
android: AudioContextAndroid(
|
|
isSpeakerphoneOn: true,
|
|
audioMode: AndroidAudioMode.normal,
|
|
contentType: AndroidContentType.sonification,
|
|
usageType: AndroidUsageType.alarm,
|
|
audioFocus: AndroidAudioFocus.gain,
|
|
),
|
|
iOS: AudioContextIOS(
|
|
category: AVAudioSessionCategory.playback,
|
|
options: {
|
|
AVAudioSessionOptions.mixWithOthers,
|
|
AVAudioSessionOptions.duckOthers,
|
|
},
|
|
),
|
|
);
|
|
|
|
Future<void> _configurePlayers() async {
|
|
for (final player in [_scanPlayer, _successPlayer, _warningPlayer]) {
|
|
await player.setReleaseMode(ReleaseMode.stop);
|
|
await player.setPlayerMode(PlayerMode.lowLatency);
|
|
await player.setVolume(1.0);
|
|
await player.setAudioContext(_loudContext);
|
|
}
|
|
}
|
|
|
|
Future<void> onCodeDetected() async {
|
|
await Future.wait([
|
|
_play(_scanPlayer, 'sounds/scan.wav'),
|
|
_vibratePattern(const [0, 80]),
|
|
HapticFeedback.mediumImpact(),
|
|
]);
|
|
}
|
|
|
|
Future<void> onSuccess() async {
|
|
await Future.wait([
|
|
_playSuccessSequence(),
|
|
_vibratePattern(const [0, 120, 60, 180]),
|
|
HapticFeedback.heavyImpact(),
|
|
]);
|
|
}
|
|
|
|
Future<void> onWarning() async {
|
|
await Future.wait([
|
|
_playWarningSequence(),
|
|
_vibratePattern(const [0, 180, 80, 180, 80, 220]),
|
|
HapticFeedback.heavyImpact(),
|
|
]);
|
|
}
|
|
|
|
Future<void> _playSuccessSequence() async {
|
|
await _play(_successPlayer, 'sounds/success.wav');
|
|
if (!kIsWeb && Platform.isAndroid) {
|
|
await Future<void>.delayed(const Duration(milliseconds: 120));
|
|
await _play(_successPlayer, 'sounds/success.wav');
|
|
}
|
|
}
|
|
|
|
Future<void> _playWarningSequence() async {
|
|
for (var i = 0; i < 2; i++) {
|
|
await _play(_warningPlayer, 'sounds/warning.wav');
|
|
if (i == 0) {
|
|
await Future<void>.delayed(const Duration(milliseconds: 140));
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _play(AudioPlayer player, String asset) async {
|
|
try {
|
|
await player.stop();
|
|
await player.play(AssetSource(asset));
|
|
} catch (_) {
|
|
await SystemSound.play(SystemSoundType.alert);
|
|
}
|
|
}
|
|
|
|
Future<void> _vibratePattern(List<int> pattern) async {
|
|
try {
|
|
final hasVibrator = await Vibration.hasVibrator();
|
|
if (hasVibrator != true) return;
|
|
|
|
final hasAmplitude = await Vibration.hasAmplitudeControl();
|
|
if (hasAmplitude == true) {
|
|
final intensities = pattern
|
|
.asMap()
|
|
.entries
|
|
.map((entry) => entry.key.isOdd ? 255 : 0)
|
|
.toList();
|
|
await Vibration.vibrate(
|
|
pattern: pattern,
|
|
intensities: intensities,
|
|
);
|
|
return;
|
|
}
|
|
|
|
await Vibration.vibrate(pattern: pattern);
|
|
} catch (_) {
|
|
await HapticFeedback.heavyImpact();
|
|
}
|
|
}
|
|
|
|
Future<void> dispose() async {
|
|
await Future.wait([
|
|
_scanPlayer.dispose(),
|
|
_successPlayer.dispose(),
|
|
_warningPlayer.dispose(),
|
|
]);
|
|
}
|
|
} |