141 lines
4.9 KiB
Dart
141 lines
4.9 KiB
Dart
import 'dart:typed_data';
|
|
import 'package:file_picker/file_picker.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../../../core/theme/app_colors.dart';
|
|
import '../../../../core/widgets/riotz_scaffold.dart';
|
|
import '../../../../core/widgets/riotz_button.dart';
|
|
import '../providers/music_providers.dart';
|
|
import '../widgets/track_card.dart';
|
|
|
|
class MusicScreen extends ConsumerStatefulWidget {
|
|
const MusicScreen({super.key});
|
|
|
|
@override
|
|
ConsumerState<MusicScreen> createState() => _MusicScreenState();
|
|
}
|
|
|
|
class _MusicScreenState extends ConsumerState<MusicScreen> {
|
|
final _titleController = TextEditingController();
|
|
final _genreController = TextEditingController();
|
|
Uint8List? _selectedMp3Bytes;
|
|
String? _selectedFileName;
|
|
String _selectedExtension = 'mp3';
|
|
|
|
@override
|
|
void dispose() {
|
|
_titleController.dispose();
|
|
_genreController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final tracksAsync = ref.watch(trackListProvider);
|
|
final uploadState = ref.watch(musicControllerProvider);
|
|
|
|
return RiotzScaffold(
|
|
appBar: AppBar(title: const Text('RIOTZ // AUDIO')),
|
|
body: ListView(
|
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 24),
|
|
children: [
|
|
Text('UPLOAD TRANSMISSION', style: theme.textTheme.labelLarge?.copyWith(color: AppColors.neonRed)),
|
|
const SizedBox(height: 16),
|
|
_UploadComposer(
|
|
titleController: _titleController,
|
|
genreController: _genreController,
|
|
selectedFileName: _selectedFileName,
|
|
isBusy: uploadState.isLoading,
|
|
onPickMp3: uploadState.isLoading ? null : _pickMp3,
|
|
onUpload: uploadState.isLoading ? null : _upload,
|
|
),
|
|
const SizedBox(height: 48),
|
|
Text('LATEST SOUNDS', style: theme.textTheme.labelLarge?.copyWith(color: AppColors.neonRed)),
|
|
const SizedBox(height: 16),
|
|
tracksAsync.when(
|
|
loading: () => const Center(child: CircularProgressIndicator(color: AppColors.neonRed)),
|
|
error: (error, _) => Center(child: Text('SIGNAL LOST: $error')),
|
|
data: (tracks) => Column(
|
|
children: tracks.map((track) => TrackCard(track: track)).toList(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _pickMp3() async {
|
|
final result = await FilePicker.platform.pickFiles(type: FileType.custom, allowedExtensions: ['mp3'], withData: true);
|
|
if (result == null || result.files.isEmpty) return;
|
|
final file = result.files.first;
|
|
setState(() {
|
|
_selectedMp3Bytes = file.bytes;
|
|
_selectedFileName = file.name.toUpperCase();
|
|
_selectedExtension = file.name.split('.').last.toLowerCase();
|
|
});
|
|
}
|
|
|
|
Future<void> _upload() async {
|
|
if (_selectedMp3Bytes == null) return;
|
|
await ref.read(musicControllerProvider.notifier).uploadTrack(
|
|
bytes: _selectedMp3Bytes!,
|
|
title: _titleController.text,
|
|
genreTag: _genreController.text,
|
|
extension: _selectedExtension,
|
|
);
|
|
setState(() {
|
|
_selectedMp3Bytes = null;
|
|
_selectedFileName = null;
|
|
_titleController.clear();
|
|
_genreController.clear();
|
|
});
|
|
}
|
|
}
|
|
|
|
class _UploadComposer extends StatelessWidget {
|
|
const _UploadComposer({
|
|
required this.titleController,
|
|
required this.genreController,
|
|
required this.selectedFileName,
|
|
required this.isBusy,
|
|
required this.onPickMp3,
|
|
required this.onUpload,
|
|
});
|
|
|
|
final TextEditingController titleController;
|
|
final TextEditingController genreController;
|
|
final String? selectedFileName;
|
|
final bool isBusy;
|
|
final VoidCallback? onPickMp3;
|
|
final VoidCallback? onUpload;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
decoration: BoxDecoration(color: AppColors.surface, border: Border.all(color: AppColors.border)),
|
|
padding: const EdgeInsets.all(20),
|
|
child: Column(
|
|
children: [
|
|
TextField(controller: titleController, decoration: const InputDecoration(hintText: 'TRACK TITLE')),
|
|
const SizedBox(height: 16),
|
|
TextField(controller: genreController, decoration: const InputDecoration(hintText: 'GENRE')),
|
|
const SizedBox(height: 24),
|
|
if (selectedFileName != null) Padding(
|
|
padding: const EdgeInsets.only(bottom: 16),
|
|
child: Text('READY: $selectedFileName', style: const TextStyle(color: AppColors.neonRed, fontWeight: FontWeight.bold, fontSize: 10)),
|
|
),
|
|
Row(
|
|
children: [
|
|
Expanded(child: RiotzButton(label: 'SELECT', style: RiotzButtonStyle.outline, onPressed: onPickMp3)),
|
|
const SizedBox(width: 12),
|
|
Expanded(child: RiotzButton(label: 'UPLOAD', isLoading: isBusy, onPressed: onUpload)),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|