flutter_audio_tagger 5.1.1 copy "flutter_audio_tagger: ^5.1.1" to clipboard
flutter_audio_tagger: ^5.1.1 copied to clipboard

PlatformAndroid

A Flutter plugin for reading and editing audio file metadata (tags) with support for multiple audio formats.

example/lib/main.dart

import 'package:flutter/material.dart';

import 'dart:io';
import 'dart:typed_data';

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter_audio_tagger/flutter_audio_tagger.dart';
import 'package:flutter_audio_tagger/tag.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Audio tagger example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.white),
      ),
      home: MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  Tag? tag;
  String? currentFilePath;
  FlutterAudioTagger flutterAudioTagger = FlutterAudioTagger();

  // Text controllers for editing
  final TextEditingController _artistController = TextEditingController();
  final TextEditingController _titleController = TextEditingController();
  final TextEditingController _albumController = TextEditingController();
  final TextEditingController _yearController = TextEditingController();
  final TextEditingController _genreController = TextEditingController();
  final TextEditingController _languageController = TextEditingController();
  final TextEditingController _composerController = TextEditingController();
  final TextEditingController _countryController = TextEditingController();
  final TextEditingController _qualityController = TextEditingController();
  final TextEditingController _lyricsController =
      TextEditingController(); // Add this line

  bool _isEditing = false;

  @override
  void dispose() {
    _artistController.dispose();
    _titleController.dispose();
    _albumController.dispose();
    _yearController.dispose();
    _genreController.dispose();
    _languageController.dispose();
    _composerController.dispose();
    _countryController.dispose();
    _qualityController.dispose();
    _lyricsController.dispose(); // Add this line
    super.dispose();
  }

  void _populateControllers() {
    _artistController.text = tag?.artist ?? '';
    _titleController.text = tag?.title ?? '';
    _albumController.text = tag?.album ?? '';
    _yearController.text = tag?.year ?? '';
    _genreController.text = tag?.genre ?? '';
    _languageController.text = tag?.language ?? '';
    _composerController.text = tag?.composer ?? '';
    _countryController.text = tag?.country ?? '';
    _qualityController.text = tag?.quality ?? '';
    _lyricsController.text = tag?.lyrics ?? '';
  }

  Future<void> _saveChanges() async {
    if (currentFilePath == null) return;

    try {
      final updatedTag = Tag(
        artist: _artistController.text.isEmpty ? null : _artistController.text,
        title: _titleController.text.isEmpty ? null : _titleController.text,
        album: _albumController.text.isEmpty ? null : _albumController.text,
        year: _yearController.text.isEmpty ? null : _yearController.text,
        genre: _genreController.text.isEmpty ? null : _genreController.text,
        language: _languageController.text.isEmpty
            ? null
            : _languageController.text,
        composer: _composerController.text.isEmpty
            ? null
            : _composerController.text,
        country: _countryController.text.isEmpty
            ? null
            : _countryController.text,
        quality: _qualityController.text.isEmpty
            ? null
            : _qualityController.text,
        lyrics: _lyricsController.text.isEmpty ? null : _lyricsController.text,
        artwork: tag?.artwork,
      );

      // Save the changes
      await flutterAudioTagger.editTags(updatedTag, currentFilePath!);

      // Force UI state update BEFORE refreshing tags
      setState(() {
        _isEditing = false;
      });

      // Refresh tags to show updated data
      tag = await flutterAudioTagger.getAllTags(currentFilePath!);
      _populateControllers();

      // Update UI again after refreshing
      setState(() {});

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Tags saved successfully!'),
          backgroundColor: Colors.green,
        ),
      );
    } on FileSystemException catch (e) {
      setState(() {
        _isEditing = false;
      });

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('File error: ${e.message}'),
          backgroundColor: Colors.red,
        ),
      );
    } on ArgumentError catch (e) {
      setState(() {
        _isEditing = false;
      });

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Invalid input: ${e.message}'),
          backgroundColor: Colors.orange,
        ),
      );
    } catch (e) {
      setState(() {
        _isEditing = false;
      });

      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Error saving tags: $e'),
          backgroundColor: Colors.red,
        ),
      );
    }
  }

  Future<void> _editArtwork() async {
    try {
      FilePickerResult? result = await FilePicker.platform.pickFiles(
        allowMultiple: false,
        type: FileType.image,
      );

      if (result != null && currentFilePath != null) {
        File imageFile = File(result.files.single.path!);

        // Check if image file exists
        if (!await imageFile.exists()) {
          throw FileSystemException('Selected image file does not exist');
        }

        // Check file size (limit to 10MB)
        int fileSize = await imageFile.length();
        if (fileSize > 10 * 1024 * 1024) {
          throw Exception('Image file too large (max 10MB)');
        }

        Uint8List imageData = await imageFile.readAsBytes();

        await flutterAudioTagger.setArtWork(imageData, currentFilePath!);

        // Refresh tags to get updated artwork
        tag = await flutterAudioTagger.getAllTags(currentFilePath!);
        setState(() {});

        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Artwork updated successfully!'),
            backgroundColor: Colors.green,
          ),
        );
      }
    } on FileSystemException catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('File error: ${e.message}'),
          backgroundColor: Colors.red,
        ),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('Error updating artwork: $e'),
          backgroundColor: Colors.red,
        ),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("AudioTagger example"),
        actions: [
          if (tag != null)
            IconButton(
              icon: Icon(_isEditing ? Icons.close : Icons.edit),
              onPressed: () {
                setState(() {
                  _isEditing = !_isEditing;
                  if (_isEditing) {
                    _populateControllers();
                  }
                });
              },
            ),
        ],
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Row(
              children: [
                Expanded(
                  child: TextButton(
                    onPressed: () async {
                      FilePickerResult?
                      result = await FilePicker.platform.pickFiles(
                        allowMultiple: false,
                        type: FileType.custom,
                        allowedExtensions: [
                          'mp3',
                          'ogg',
                          'flac',
                          'aiff',
                          'wav',
                          'wma',
                          'dsf',
                        ],
                        /* supported formats : Mp3, Flac, OggVorbis, Mp4, Aiff, Wav, Wma, dsf */
                      );

                      if (result != null) {
                        currentFilePath = result.files.single.path!;
                        tag = await flutterAudioTagger.getAllTags(
                          currentFilePath!,
                        );
                        _populateControllers();
                        setState(() {
                          _isEditing = false;
                        });
                      }
                    },
                    child: Text("Pick Music"),
                  ),
                ),
                if (_isEditing) ...[
                  SizedBox(width: 8),
                  ElevatedButton(onPressed: _saveChanges, child: Text("Save")),
                ],
              ],
            ),
          ),
          Expanded(
            child: tag != null
                ? _buildTagCards()
                : Center(child: Text("No music selected")),
          ),
        ],
      ),
    );
  }

  Widget _buildTagCards() {
    return SingleChildScrollView(
      padding: EdgeInsets.all(16),
      child: Column(
        children: [
          _buildArtworkCard(),
          _buildEditableInfoCard("Artist", _artistController),
          _buildEditableInfoCard("Title", _titleController),
          _buildEditableInfoCard("Album", _albumController),
          _buildEditableInfoCard("Year", _yearController),
          _buildEditableInfoCard("Genre", _genreController),
          _buildEditableInfoCard("Language", _languageController),
          _buildEditableInfoCard("Composer", _composerController),
          _buildEditableInfoCard("Country", _countryController),
          _buildEditableInfoCard("Quality", _qualityController),
          _buildEditableLyricsCard(),
        ],
      ),
    );
  }

  Widget _buildArtworkCard() {
    return Card(
      margin: EdgeInsets.only(bottom: 16),
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  "Artwork",
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                ),
                if (_isEditing)
                  TextButton.icon(
                    onPressed: _editArtwork,
                    icon: Icon(Icons.edit),
                    label: Text("Edit"),
                  ),
              ],
            ),
            SizedBox(height: 8),
            Center(
              child: Container(
                width: 200,
                height: 200,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(8),
                  color: Colors.grey[300],
                  image: tag?.artwork != null
                      ? DecorationImage(
                          image: MemoryImage(tag!.artwork!),
                          fit: BoxFit.cover,
                        )
                      : null,
                ),
                child: tag?.artwork == null
                    ? Icon(Icons.music_note, size: 80, color: Colors.grey[600])
                    : null,
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildEditableInfoCard(
    String title,
    TextEditingController controller,
  ) {
    return Card(
      margin: EdgeInsets.only(bottom: 8),
      child: ListTile(
        title: Text(title, style: TextStyle(fontWeight: FontWeight.bold)),
        subtitle: _isEditing
            ? TextField(
                controller: controller,
                decoration: InputDecoration(
                  hintText: "Enter $title",
                  border: UnderlineInputBorder(),
                ),
              )
            : Text(
                controller.text.isEmpty ? "Not set" : controller.text,
                style: TextStyle(
                  fontSize: 16,
                  color: controller.text.isEmpty ? Colors.grey : null,
                ),
              ),
      ),
    );
  }

  // Add this new method for lyrics (multiline text field)
  Widget _buildEditableLyricsCard() {
    return Card(
      margin: EdgeInsets.only(bottom: 8),
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              "Lyrics",
              style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
            ),
            SizedBox(height: 8),
            _isEditing
                ? TextField(
                    controller: _lyricsController,
                    maxLines: 6,
                    decoration: InputDecoration(
                      hintText: "Enter lyrics",
                      border: OutlineInputBorder(),
                    ),
                  )
                : Container(
                    width: double.infinity,
                    padding: EdgeInsets.all(12),
                    decoration: BoxDecoration(
                      border: Border.all(color: Colors.grey[300]!),
                      borderRadius: BorderRadius.circular(8),
                    ),
                    child: Text(
                      _lyricsController.text.isEmpty
                          ? "No lyrics available"
                          : _lyricsController.text,
                      style: TextStyle(
                        fontSize: 14,
                        color: _lyricsController.text.isEmpty
                            ? Colors.grey
                            : null,
                      ),
                    ),
                  ),
          ],
        ),
      ),
    );
  }
}
4
likes
140
points
245
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for reading and editing audio file metadata (tags) with support for multiple audio formats.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_audio_tagger

Packages that implement flutter_audio_tagger