first commit

This commit is contained in:
Lucas Saburido
2026-05-13 16:26:45 +01:00
commit cabf2025cd
252 changed files with 13524 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
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)),
],
),
],
),
);
}
}