spotify integration works
This commit is contained in:
parent
f70fe3cdd1
commit
025eee7644
11 changed files with 1637 additions and 717 deletions
204
CHALLENGE_2/sleepysound/lib/services/music_queue_service.dart
Normal file
204
CHALLENGE_2/sleepysound/lib/services/music_queue_service.dart
Normal file
|
@ -0,0 +1,204 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import '../models/spotify_track.dart';
|
||||
import '../services/spotify_service.dart';
|
||||
|
||||
class QueueItem {
|
||||
final SpotifyTrack track;
|
||||
int votes;
|
||||
bool userVoted;
|
||||
final DateTime addedAt;
|
||||
|
||||
QueueItem({
|
||||
required this.track,
|
||||
this.votes = 1,
|
||||
this.userVoted = true,
|
||||
DateTime? addedAt,
|
||||
}) : addedAt = addedAt ?? DateTime.now();
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': track.id,
|
||||
'title': track.name,
|
||||
'artist': track.artistNames,
|
||||
'votes': votes,
|
||||
'userVoted': userVoted,
|
||||
'duration': track.duration,
|
||||
'imageUrl': track.imageUrl,
|
||||
'addedAt': addedAt.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
class MusicQueueService extends ChangeNotifier {
|
||||
static final MusicQueueService _instance = MusicQueueService._internal();
|
||||
factory MusicQueueService() => _instance;
|
||||
MusicQueueService._internal();
|
||||
|
||||
final SpotifyService _spotifyService = SpotifyService();
|
||||
|
||||
// Current playing track
|
||||
SpotifyTrack? _currentTrack;
|
||||
bool _isPlaying = false;
|
||||
double _progress = 0.0;
|
||||
|
||||
// Queue management
|
||||
final List<QueueItem> _queue = [];
|
||||
|
||||
// Recently played
|
||||
final List<SpotifyTrack> _recentlyPlayed = [];
|
||||
|
||||
// Getters
|
||||
SpotifyTrack? get currentTrack => _currentTrack;
|
||||
bool get isPlaying => _isPlaying;
|
||||
double get progress => _progress;
|
||||
List<QueueItem> get queue => List.unmodifiable(_queue);
|
||||
List<SpotifyTrack> get recentlyPlayed => List.unmodifiable(_recentlyPlayed);
|
||||
|
||||
// Queue operations
|
||||
void addToQueue(SpotifyTrack track) {
|
||||
// Check if track is already in queue
|
||||
final existingIndex = _queue.indexWhere((item) => item.track.id == track.id);
|
||||
|
||||
if (existingIndex != -1) {
|
||||
// If track exists, upvote it
|
||||
upvote(existingIndex);
|
||||
} else {
|
||||
// Add new track to queue
|
||||
final queueItem = QueueItem(track: track);
|
||||
_queue.add(queueItem);
|
||||
_sortQueue();
|
||||
notifyListeners();
|
||||
print('Added "${track.name}" by ${track.artistNames} to queue');
|
||||
}
|
||||
}
|
||||
|
||||
void upvote(int index) {
|
||||
if (index >= 0 && index < _queue.length) {
|
||||
_queue[index].votes++;
|
||||
if (!_queue[index].userVoted) {
|
||||
_queue[index].userVoted = true;
|
||||
}
|
||||
_sortQueue();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void downvote(int index) {
|
||||
if (index >= 0 && index < _queue.length) {
|
||||
if (_queue[index].votes > 0) {
|
||||
_queue[index].votes--;
|
||||
}
|
||||
_sortQueue();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void _sortQueue() {
|
||||
_queue.sort((a, b) {
|
||||
// First sort by votes (descending)
|
||||
final voteComparison = b.votes.compareTo(a.votes);
|
||||
if (voteComparison != 0) return voteComparison;
|
||||
|
||||
// If votes are equal, sort by time added (ascending - first come first serve)
|
||||
return a.addedAt.compareTo(b.addedAt);
|
||||
});
|
||||
}
|
||||
|
||||
// Playback simulation
|
||||
void playNext() {
|
||||
if (_queue.isNotEmpty) {
|
||||
final nextItem = _queue.removeAt(0);
|
||||
_currentTrack = nextItem.track;
|
||||
_isPlaying = true;
|
||||
_progress = 0.0;
|
||||
|
||||
// Add to recently played
|
||||
_recentlyPlayed.insert(0, nextItem.track);
|
||||
if (_recentlyPlayed.length > 10) {
|
||||
_recentlyPlayed.removeLast();
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
print('Now playing: ${_currentTrack!.name} by ${_currentTrack!.artistNames}');
|
||||
|
||||
// Simulate track progress
|
||||
_simulatePlayback();
|
||||
}
|
||||
}
|
||||
|
||||
void togglePlayPause() {
|
||||
_isPlaying = !_isPlaying;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void skipTrack() {
|
||||
playNext();
|
||||
}
|
||||
|
||||
void _simulatePlayback() {
|
||||
if (_currentTrack == null) return;
|
||||
|
||||
// Simulate track progress over time
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
if (_isPlaying && _currentTrack != null) {
|
||||
_progress += 1.0 / (_currentTrack!.durationMs / 1000);
|
||||
if (_progress >= 1.0) {
|
||||
// Track finished, play next
|
||||
playNext();
|
||||
} else {
|
||||
notifyListeners();
|
||||
_simulatePlayback();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize with some popular tracks
|
||||
Future<void> initializeQueue() async {
|
||||
if (_queue.isEmpty && _currentTrack == null) {
|
||||
try {
|
||||
final popularTracks = await _spotifyService.getPopularTracks();
|
||||
for (final track in popularTracks.take(4)) {
|
||||
final queueItem = QueueItem(
|
||||
track: track,
|
||||
votes: 10 - popularTracks.indexOf(track) * 2, // Decreasing votes
|
||||
userVoted: false,
|
||||
);
|
||||
_queue.add(queueItem);
|
||||
}
|
||||
|
||||
// Start playing the first track
|
||||
if (_queue.isNotEmpty) {
|
||||
playNext();
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
} catch (e) {
|
||||
print('Error initializing queue: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search functionality
|
||||
Future<List<SpotifyTrack>> searchTracks(String query) async {
|
||||
return await _spotifyService.searchTracks(query, limit: 20);
|
||||
}
|
||||
|
||||
// Get queue as JSON for display
|
||||
List<Map<String, dynamic>> get queueAsJson {
|
||||
return _queue.map((item) => item.toJson()).toList();
|
||||
}
|
||||
|
||||
// Get current track info for display
|
||||
Map<String, dynamic>? get currentTrackInfo {
|
||||
if (_currentTrack == null) return null;
|
||||
|
||||
return {
|
||||
'title': _currentTrack!.name,
|
||||
'artist': _currentTrack!.artistNames,
|
||||
'album': _currentTrack!.album.name,
|
||||
'imageUrl': _currentTrack!.imageUrl,
|
||||
'duration': _currentTrack!.duration,
|
||||
'progress': _progress,
|
||||
'isPlaying': _isPlaying,
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue