🎵 Аудиоплеер

Слой 1+2: Решение и Логика

Стандартный аудиоплеер во FlutterFlow иногда имеет ограничения в Web-версии или требует сложной настройки. Данный кастомный виджет на базе библиотеки just_audio работает стабильно на всех платформах и поддерживает фоновое воспроизведение.

Основные возможности:

  • Полная поддержка Web (в отличие от некоторых встроенных решений).
  • Кастомизация интерфейса (цвета, прогресс-бар).
  • Работа с заблокированным экраном (для мобильных устройств).

Параметры виджета:

  1. audioUrl (String): прямая ссылка на аудиофайл.
  2. name (String): название трека для отображения.
  3. showProgressBar (bool): переключатель видимости шкалы прогресса.

💻 Код виджета (Вариант 1)

Вы можете скопировать этот код и вставить его в раздел Custom Widgets во FlutterFlow. Не забудьте добавить зависимость just_audio в Pubspec Dependencies.

import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart';
 
class MusicWidget extends StatefulWidget {
 const MusicWidget({
 super.key,
 this.width,
 this.height,
 required this.audioUrl,
 required this.showProgressBar,
 required this.name,
 });
 
 final double? width;
 final double? height;
 final String audioUrl;
 final bool showProgressBar;
 final String name;
 
 @override
 State<MusicWidget> createState() => _MusicWidgetState();
}
 
class _MusicWidgetState extends State<MusicWidget> {
 late AudioPlayer _audioPlayer;
 bool _isPlaying = false;
 
 @override
 void initState() {
 super.initState();
 _audioPlayer = AudioPlayer();
 _loadAudio();
 }
 
 Future<void> _loadAudio() async {
 try {
 await _audioPlayer.setUrl(widget.audioUrl);
 } catch (e) {
 print("Error loading audio: $e");
 }
 }
 
 void _togglePlayPause() async {
 setState(() {
 _isPlaying = !_isPlaying;
 });
 
 if (_isPlaying) {
 await _audioPlayer.play();
 } else {
 await _audioPlayer.pause();
 }
 }
 
 @override
 void dispose() {
 _audioPlayer.dispose();
 super.dispose();
 }
 
 @override
 Widget build(BuildContext context) {
 return Container(
 decoration: BoxDecoration(
 color: Color(0xFF1C0335),
 borderRadius: BorderRadius.circular(10),
 ),
 padding: const EdgeInsets.all(12),
 child: Column(
 mainAxisAlignment: MainAxisAlignment.center,
 children: [
 Text(
 widget.name,
 style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white),
 ),
 const SizedBox(height: 15),
 IconButton(
 icon: Icon(
 _isPlaying ? Icons.pause_circle_filled : Icons.play_circle_filled,
 color: Colors.white,
 size: 50,
 ),
 onPressed: _togglePlayPause,
 ),
 if (widget.showProgressBar)
 StreamBuilder<Duration>(
 stream: _audioPlayer.positionStream,
 builder: (context, snapshot) {
 final position = snapshot.data ?? Duration.zero;
 final duration = _audioPlayer.duration ?? Duration.zero;
 return Slider(
 value: position.inSeconds.toDouble(),
 max: duration.inSeconds.toDouble(),
 onChanged: (value) => _audioPlayer.seek(Duration(seconds: value.toInt())),
 activeColor: Colors.white,
 inactiveColor: Colors.white24,
 );
 },
 ),
 ],
 ),
 );
 }
}

Слой 3: Источники (Proven Roots)