I’m writing a ChatApp in Dart, i’ve found a problem when writing my custom Voice Message widget using:audio_waveforms: ^1.0.5
I’ve done so but i didn’t found a method to cache the voice message widget this causes to have very long loading times and when you send a new voice message it brakes, it creates a new message but it contains the upper one and only after you rerender the chatpage it corrects himself. Here’s the code:
<code>import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
class AudioMessageBeta extends StatefulWidget {
final String id;
final String audioUrl;
final String message;
const AudioMessageBeta(
{super.key,
required this.audioUrl,
required this.message,
required this.id});
@override
State<AudioMessageBeta> createState() => _AudioMessageBetaState();
}
class _AudioMessageBetaState extends State<AudioMessageBeta> {
bool isLoading = false;
final PlayerController playerController = new PlayerController();
StreamSubscription<PlayerState>? playerStateSubsription;
Future<dynamic> downloadFile(String url) async {
String dir = (await getApplicationDocumentsDirectory()).path;
if (await File("$dir/${widget.id}.mp3").exists()) {
return "$dir/${widget.id}.mp3";
} else {
File file = File("$dir/${widget.id}.mp3");
var request = await http.get(
Uri.parse(url),
);
var bytes = request.bodyBytes;
await file.writeAsBytes(bytes);
return file.path;
}
}
void prepareVoice() async {
await playerController.preparePlayer(
path: await downloadFile(widget.audioUrl),
shouldExtractWaveform: true,
noOfSamples: (MediaQuery.of(context).size.width * 0.5) ~/ 5);
}
@override
void initState() {
isLoading = true;
Future.delayed(const Duration(milliseconds: 200), () {
prepareVoice();
playerStateSubsription =
playerController.onPlayerStateChanged.listen((PlayerState) {
setState(() {});
});
});
super.initState();
isLoading = false;
}
@override
void dispose() {
if (mounted) {
playerController.dispose();
playerStateSubsription!.cancel();
}
super.dispose();
}
void playVoice() async {
switch (playerController.playerState) {
case PlayerState.playing:
await playerController.pausePlayer();
break;
default:
await playerController.startPlayer(finishMode: FinishMode.pause);
}
}
@override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.75,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListTile(
contentPadding: const EdgeInsets.all(0),
horizontalTitleGap: 8,
leading: GestureDetector(
onTap: () => playVoice(),
child: SizedBox(
height: 45,
width: 45,
child: CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.background,
child: isLoading
? const CircularProgressIndicator()
: Icon(playerController.playerState.isPlaying
? Icons.pause_rounded
: Icons.play_arrow),
),
),
),
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: AudioFileWaveforms(
size: Size(MediaQuery.of(context).size.width * 0.5, 25),
playerController: playerController,
enableSeekGesture: true,
continuousWaveform: false,
waveformType: WaveformType.fitWidth,
playerWaveStyle: PlayerWaveStyle(
fixedWaveColor: Theme.of(context).colorScheme.background,
liveWaveColor: Colors.white,
spacing: 5,
waveThickness: 2.5,
scaleFactor: 200,
),
),
),
),
),
);
}
}
</code>
<code>import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
class AudioMessageBeta extends StatefulWidget {
final String id;
final String audioUrl;
final String message;
const AudioMessageBeta(
{super.key,
required this.audioUrl,
required this.message,
required this.id});
@override
State<AudioMessageBeta> createState() => _AudioMessageBetaState();
}
class _AudioMessageBetaState extends State<AudioMessageBeta> {
bool isLoading = false;
final PlayerController playerController = new PlayerController();
StreamSubscription<PlayerState>? playerStateSubsription;
Future<dynamic> downloadFile(String url) async {
String dir = (await getApplicationDocumentsDirectory()).path;
if (await File("$dir/${widget.id}.mp3").exists()) {
return "$dir/${widget.id}.mp3";
} else {
File file = File("$dir/${widget.id}.mp3");
var request = await http.get(
Uri.parse(url),
);
var bytes = request.bodyBytes;
await file.writeAsBytes(bytes);
return file.path;
}
}
void prepareVoice() async {
await playerController.preparePlayer(
path: await downloadFile(widget.audioUrl),
shouldExtractWaveform: true,
noOfSamples: (MediaQuery.of(context).size.width * 0.5) ~/ 5);
}
@override
void initState() {
isLoading = true;
Future.delayed(const Duration(milliseconds: 200), () {
prepareVoice();
playerStateSubsription =
playerController.onPlayerStateChanged.listen((PlayerState) {
setState(() {});
});
});
super.initState();
isLoading = false;
}
@override
void dispose() {
if (mounted) {
playerController.dispose();
playerStateSubsription!.cancel();
}
super.dispose();
}
void playVoice() async {
switch (playerController.playerState) {
case PlayerState.playing:
await playerController.pausePlayer();
break;
default:
await playerController.startPlayer(finishMode: FinishMode.pause);
}
}
@override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.75,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListTile(
contentPadding: const EdgeInsets.all(0),
horizontalTitleGap: 8,
leading: GestureDetector(
onTap: () => playVoice(),
child: SizedBox(
height: 45,
width: 45,
child: CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.background,
child: isLoading
? const CircularProgressIndicator()
: Icon(playerController.playerState.isPlaying
? Icons.pause_rounded
: Icons.play_arrow),
),
),
),
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: AudioFileWaveforms(
size: Size(MediaQuery.of(context).size.width * 0.5, 25),
playerController: playerController,
enableSeekGesture: true,
continuousWaveform: false,
waveformType: WaveformType.fitWidth,
playerWaveStyle: PlayerWaveStyle(
fixedWaveColor: Theme.of(context).colorScheme.background,
liveWaveColor: Colors.white,
spacing: 5,
waveThickness: 2.5,
scaleFactor: 200,
),
),
),
),
),
);
}
}
</code>
import 'dart:async';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
class AudioMessageBeta extends StatefulWidget {
final String id;
final String audioUrl;
final String message;
const AudioMessageBeta(
{super.key,
required this.audioUrl,
required this.message,
required this.id});
@override
State<AudioMessageBeta> createState() => _AudioMessageBetaState();
}
class _AudioMessageBetaState extends State<AudioMessageBeta> {
bool isLoading = false;
final PlayerController playerController = new PlayerController();
StreamSubscription<PlayerState>? playerStateSubsription;
Future<dynamic> downloadFile(String url) async {
String dir = (await getApplicationDocumentsDirectory()).path;
if (await File("$dir/${widget.id}.mp3").exists()) {
return "$dir/${widget.id}.mp3";
} else {
File file = File("$dir/${widget.id}.mp3");
var request = await http.get(
Uri.parse(url),
);
var bytes = request.bodyBytes;
await file.writeAsBytes(bytes);
return file.path;
}
}
void prepareVoice() async {
await playerController.preparePlayer(
path: await downloadFile(widget.audioUrl),
shouldExtractWaveform: true,
noOfSamples: (MediaQuery.of(context).size.width * 0.5) ~/ 5);
}
@override
void initState() {
isLoading = true;
Future.delayed(const Duration(milliseconds: 200), () {
prepareVoice();
playerStateSubsription =
playerController.onPlayerStateChanged.listen((PlayerState) {
setState(() {});
});
});
super.initState();
isLoading = false;
}
@override
void dispose() {
if (mounted) {
playerController.dispose();
playerStateSubsription!.cancel();
}
super.dispose();
}
void playVoice() async {
switch (playerController.playerState) {
case PlayerState.playing:
await playerController.pausePlayer();
break;
default:
await playerController.startPlayer(finishMode: FinishMode.pause);
}
}
@override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.75,
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListTile(
contentPadding: const EdgeInsets.all(0),
horizontalTitleGap: 8,
leading: GestureDetector(
onTap: () => playVoice(),
child: SizedBox(
height: 45,
width: 45,
child: CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.background,
child: isLoading
? const CircularProgressIndicator()
: Icon(playerController.playerState.isPlaying
? Icons.pause_rounded
: Icons.play_arrow),
),
),
),
title: Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: AudioFileWaveforms(
size: Size(MediaQuery.of(context).size.width * 0.5, 25),
playerController: playerController,
enableSeekGesture: true,
continuousWaveform: false,
waveformType: WaveformType.fitWidth,
playerWaveStyle: PlayerWaveStyle(
fixedWaveColor: Theme.of(context).colorScheme.background,
liveWaveColor: Colors.white,
spacing: 5,
waveThickness: 2.5,
scaleFactor: 200,
),
),
),
),
),
);
}
}
I’ve tried several methods but i can’t geti it to work, i’m also a newbie in Flutter.