first commit
This commit is contained in:
140
lib/features/music/presentation/screens/music_screen.dart
Normal file
140
lib/features/music/presentation/screens/music_screen.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user