-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: MusicRepository * feat: interactive music player * fix: tracks count * test: fixed failing
- Loading branch information
Showing
25 changed files
with
1,553 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" | ||
#include "Generated.xcconfig" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" | ||
#include "Generated.xcconfig" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Uncomment this line to define a global platform for your project | ||
# platform :ios, '12.0' | ||
|
||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. | ||
ENV['COCOAPODS_DISABLE_STATS'] = 'true' | ||
|
||
project 'Runner', { | ||
'Debug' => :debug, | ||
'Profile' => :release, | ||
'Release' => :release, | ||
} | ||
|
||
def flutter_root | ||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) | ||
unless File.exist?(generated_xcode_build_settings_path) | ||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" | ||
end | ||
|
||
File.foreach(generated_xcode_build_settings_path) do |line| | ||
matches = line.match(/FLUTTER_ROOT\=(.*)/) | ||
return matches[1].strip if matches | ||
end | ||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" | ||
end | ||
|
||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) | ||
|
||
flutter_ios_podfile_setup | ||
|
||
target 'Runner' do | ||
use_frameworks! | ||
use_modular_headers! | ||
|
||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) | ||
target 'RunnerTests' do | ||
inherit! :search_paths | ||
end | ||
end | ||
|
||
post_install do |installer| | ||
installer.pods_project.targets.each do |target| | ||
flutter_additional_ios_build_settings(target) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
PODS: | ||
- audio_session (0.0.1): | ||
- Flutter | ||
- Flutter (1.0.0) | ||
- just_audio (0.0.1): | ||
- Flutter | ||
- path_provider_foundation (0.0.1): | ||
- Flutter | ||
- FlutterMacOS | ||
|
||
DEPENDENCIES: | ||
- audio_session (from `.symlinks/plugins/audio_session/ios`) | ||
- Flutter (from `Flutter`) | ||
- just_audio (from `.symlinks/plugins/just_audio/ios`) | ||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) | ||
|
||
EXTERNAL SOURCES: | ||
audio_session: | ||
:path: ".symlinks/plugins/audio_session/ios" | ||
Flutter: | ||
:path: Flutter | ||
just_audio: | ||
:path: ".symlinks/plugins/just_audio/ios" | ||
path_provider_foundation: | ||
:path: ".symlinks/plugins/path_provider_foundation/darwin" | ||
|
||
SPEC CHECKSUMS: | ||
audio_session: 088d2483ebd1dc43f51d253d4a1c517d9a2e7207 | ||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 | ||
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa | ||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 | ||
|
||
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 | ||
|
||
COCOAPODS: 1.15.2 |
Large diffs are not rendered by default.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export 'music_player_cubit.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:bloc/bloc.dart'; | ||
import 'package:equatable/equatable.dart'; | ||
import 'package:just_audio/just_audio.dart'; | ||
import 'package:music_repository/music_repository.dart'; | ||
|
||
part 'music_player_state.dart'; | ||
|
||
class MusicPlayerCubit extends Cubit<MusicPlayerState> { | ||
MusicPlayerCubit({ | ||
required MusicRepository musicRepository, | ||
required AudioPlayer player, | ||
}) : _musicRepository = musicRepository, | ||
_player = player, | ||
super(const MusicPlayerState()) { | ||
_isPlayingSubscription = _player.playingStream.listen(_onIsPlayingChanged); | ||
_progressSubscription = _player.positionStream.listen(_onProgressChanged); | ||
_trackSubscription = | ||
_player.currentIndexStream.listen(_onTrackIndexChanged); | ||
} | ||
|
||
final MusicRepository _musicRepository; | ||
late final StreamSubscription<bool> _isPlayingSubscription; | ||
late final StreamSubscription<Duration> _progressSubscription; | ||
late final StreamSubscription<int?> _trackSubscription; | ||
final AudioPlayer _player; | ||
|
||
void _onIsPlayingChanged(bool isPlaying) { | ||
emit(state.copyWith(isPlaying: isPlaying)); | ||
} | ||
|
||
void _onProgressChanged(Duration position) { | ||
final duration = _player.duration; | ||
if (duration == null) return; | ||
final progress = position.inMilliseconds / duration.inMilliseconds; | ||
emit(state.copyWith(progress: progress)); | ||
} | ||
|
||
void _onTrackIndexChanged(int? index) { | ||
if (index == null) { | ||
emit(MusicPlayerState(tracks: state.tracks)); | ||
} else { | ||
emit(state.copyWith(currentTrackIndex: index)); | ||
} | ||
} | ||
|
||
void initialize() { | ||
final tracks = _musicRepository.getTracks(); | ||
|
||
if (_player.audioSource == null) { | ||
final playlist = ConcatenatingAudioSource( | ||
children: tracks.map((track) => AudioSource.asset(track.path)).toList(), | ||
); | ||
_player.setAudioSource(playlist); | ||
} | ||
|
||
emit(state.copyWith(tracks: tracks)); | ||
} | ||
|
||
void playTrack(MusicTrack track) { | ||
if (track == state.currentTrack) { | ||
return togglePlayPause(); | ||
} | ||
_player | ||
..seek(Duration.zero, index: track.index) | ||
..play(); | ||
} | ||
|
||
void togglePlayPause() { | ||
if (state.currentTrack == null) return; | ||
if (state.isPlaying) { | ||
_player.pause(); | ||
} else { | ||
_player.play(); | ||
} | ||
} | ||
|
||
void seek(double progress) { | ||
final duration = _player.duration; | ||
if (duration != null) { | ||
_player.seek(duration * progress); | ||
} | ||
} | ||
|
||
void next() { | ||
if (state.currentTrack == null) return; | ||
_player.seekToNext(); | ||
} | ||
|
||
void previous() { | ||
if (state.currentTrack == null) return; | ||
_player.seekToPrevious(); | ||
} | ||
|
||
void toggleLoop() { | ||
final loop = !state.isLoop; | ||
_player.setLoopMode(loop ? LoopMode.one : LoopMode.off); | ||
emit(state.copyWith(isLoop: !state.isLoop)); | ||
} | ||
|
||
void toggleShuffle() { | ||
final shuffle = !state.isShuffle; | ||
_player.setShuffleModeEnabled(shuffle); | ||
emit(state.copyWith(isShuffle: !state.isShuffle)); | ||
} | ||
|
||
@override | ||
Future<void> close() { | ||
_isPlayingSubscription.cancel(); | ||
_progressSubscription.cancel(); | ||
_trackSubscription.cancel(); | ||
return super.close(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
part of 'music_player_cubit.dart'; | ||
|
||
class MusicPlayerState extends Equatable { | ||
const MusicPlayerState({ | ||
this.tracks = const [], | ||
this.currentTrackIndex, | ||
this.progress = 0.0, | ||
this.isPlaying = false, | ||
this.isLoop = false, | ||
this.isShuffle = false, | ||
}); | ||
|
||
final List<MusicTrack> tracks; | ||
final int? currentTrackIndex; | ||
final double progress; | ||
final bool isPlaying; | ||
final bool isLoop; | ||
final bool isShuffle; | ||
|
||
MusicTrack? get currentTrack => tracks.isNotEmpty && currentTrackIndex != null | ||
? tracks[currentTrackIndex!] | ||
: null; | ||
|
||
@override | ||
List<Object?> get props => [ | ||
tracks, | ||
currentTrackIndex, | ||
isPlaying, | ||
progress, | ||
isLoop, | ||
isShuffle, | ||
]; | ||
|
||
MusicPlayerState copyWith({ | ||
List<MusicTrack>? tracks, | ||
int? currentTrackIndex, | ||
double? progress, | ||
bool? isPlaying, | ||
bool? isLoop, | ||
bool? isShuffle, | ||
}) { | ||
return MusicPlayerState( | ||
tracks: tracks ?? this.tracks, | ||
currentTrackIndex: currentTrackIndex ?? this.currentTrackIndex, | ||
isPlaying: isPlaying ?? this.isPlaying, | ||
progress: progress ?? this.progress, | ||
isLoop: isLoop ?? this.isLoop, | ||
isShuffle: isShuffle ?? this.isShuffle, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export 'cubit/cubit.dart'; | ||
export 'view/view.dart'; | ||
export 'widgets/widgets.dart'; |
Oops, something went wrong.