import 'package:flutter/material.dart'; import 'package:file_picker/file_picker.dart'; import 'package:firebase_storage/firebase_storage.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import 'dart:typed_data'; class AdminMusicScreen extends StatefulWidget { const AdminMusicScreen({super.key}); @override State createState() => _AdminMusicScreenState(); } class _AdminMusicScreenState extends State { final _titleController = TextEditingController(); PlatformFile? _audioFile; PlatformFile? _imageFile; bool _isUploading = false; double _uploadProgress = 0; static const Color terminalGreen = Color(0xFF00FF00); Future _pickAudio() async { final result = await FilePicker.platform.pickFiles(type: FileType.audio, withData: true); if (result != null) setState(() => _audioFile = result.files.first); } Future _pickImage() async { final result = await FilePicker.platform.pickFiles(type: FileType.image, withData: true); if (result != null) setState(() => _imageFile = result.files.first); } Future _uploadTrack() async { if (_audioFile == null || _imageFile == null || _titleController.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("SYSTEM_ERROR: DATA_REQUIRED"))); return; } setState(() { _isUploading = true; _uploadProgress = 0; }); try { // 1. DYNAMIC CONTENT TYPE DETECTION String audioContentType = 'audio/mpeg'; // Default MP3 if (_audioFile!.name.toLowerCase().endsWith('.wav')) audioContentType = 'audio/wav'; if (_audioFile!.name.toLowerCase().endsWith('.m4a')) audioContentType = 'audio/mp4'; // 2. UPLOAD AUDIO final audioPath = 'music/${DateTime.now().millisecondsSinceEpoch}_${_audioFile!.name}'; final audioUploadTask = FirebaseStorage.instance.ref().child(audioPath).putData( _audioFile!.bytes!, SettableMetadata(contentType: audioContentType), ); audioUploadTask.snapshotEvents.listen((event) { setState(() => _uploadProgress = event.bytesTransferred / event.totalBytes); }); final audioUrl = await (await audioUploadTask).ref.getDownloadURL(); // 3. UPLOAD IMAGE final imagePath = 'covers/${DateTime.now().millisecondsSinceEpoch}_${_imageFile!.name}'; final imageUrl = await (await FirebaseStorage.instance.ref().child(imagePath).putData( _imageFile!.bytes!, SettableMetadata(contentType: 'image/jpeg'), )).ref.getDownloadURL(); // 4. SAVE TO FIRESTORE await FirebaseFirestore.instance.collection('tracks').add({ 'title': _titleController.text.trim(), 'audioUrl': audioUrl, 'imageUrl': imageUrl, 'fileName': _audioFile!.name, // Storing this for the dynamic extension display 'uploadedAt': FieldValue.serverTimestamp(), }); if (!mounted) return; Navigator.pop(context); } catch (e) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("EXECUTION_ERROR: $e"))); } finally { setState(() => _isUploading = false); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: AppBar(title: const Text("REGISTER_NEW_ASSET"), centerTitle: true), body: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( children: [ TextField(controller: _titleController, decoration: const InputDecoration(labelText: "ASSET_TITLE")), const SizedBox(height: 25), _buildFileSlot("AUDIO_SOURCE", _audioFile?.name, Icons.audiotrack, _pickAudio), const SizedBox(height: 15), _buildFileSlot("VISUAL_ASSET", _imageFile?.name, Icons.image, _pickImage), const SizedBox(height: 40), if (_isUploading) ...[ LinearProgressIndicator(value: _uploadProgress, color: terminalGreen, backgroundColor: Colors.white10), const SizedBox(height: 10), Text("${(_uploadProgress * 100).toStringAsFixed(0)}%_SYNCING", style: const TextStyle(fontSize: 10)), ] else SizedBox(width: double.infinity, child: ElevatedButton(onPressed: _uploadTrack, child: const Text("[ RELEASE_TRACK ]"))), ], ), ), ); } Widget _buildFileSlot(String label, String? fileName, IconData icon, VoidCallback onTap) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: const TextStyle(color: Colors.white24, fontSize: 10)), const SizedBox(height: 5), InkWell( onTap: onTap, child: Container( padding: const EdgeInsets.all(15), decoration: BoxDecoration(border: Border.all(color: fileName == null ? Colors.white10 : terminalGreen)), child: Row( children: [ Icon(icon, color: fileName == null ? Colors.grey : terminalGreen, size: 20), const SizedBox(width: 15), Expanded(child: Text(fileName ?? "SELECT_FILE...", style: TextStyle(color: fileName == null ? Colors.grey : Colors.white, fontSize: 14), overflow: TextOverflow.ellipsis)), const Text("[ BROWSE ]", style: TextStyle(color: terminalGreen, fontSize: 10)), ], ), ), ), ], ); } }