Skip to content

Commit

Permalink
Added player bottom app bar drag up to show player controls.
Browse files Browse the repository at this point in the history
Fixed player bottom app bar swipe bugs.
Bug fixes and improvements.
  • Loading branch information
ShokhrukhbekYuldoshev committed Apr 8, 2024
1 parent 8f22bf3 commit ae9e28b
Show file tree
Hide file tree
Showing 22 changed files with 430 additions and 309 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Meloplay is a local music player app that plays music from your device built wit
- [x] Share music
- [x] Settings
- [x] Themes (multiple themes)
- [ ] Localization

## 📸 Screenshots

Expand Down
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive_flutter/adapters.dart';
import 'package:meloplay/src/bloc/search/search_bloc.dart';
import 'package:permission_handler/permission_handler.dart';

import 'package:meloplay/src/app.dart';
import 'package:meloplay/src/bloc/favorites/favorites_bloc.dart';
import 'package:meloplay/src/bloc/home/home_bloc.dart';
import 'package:meloplay/src/bloc/player/player_bloc.dart';
import 'package:meloplay/src/bloc/recents/recents_bloc.dart';
import 'package:meloplay/src/bloc/search/search_bloc.dart';
import 'package:meloplay/src/bloc/song/song_bloc.dart';
import 'package:meloplay/src/bloc/theme/theme_bloc.dart';
import 'package:meloplay/src/core/di/service_locator.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/bloc/player/player_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class PlayerBloc extends Bloc<PlayerEvent, PlayerState> {

on<PlayerSeek>((event, emit) async {
try {
await repository.seek(event.position);
await repository.seek(event.position, index: event.index);
emit(PlayerSeeked(event.position));
} catch (e) {
emit(PlayerError(e.toString()));
Expand Down
3 changes: 2 additions & 1 deletion lib/src/bloc/player/player_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ class PlayerStop extends PlayerEvent {}

class PlayerSeek extends PlayerEvent {
final Duration position;
final int? index;

PlayerSeek(this.position);
PlayerSeek(this.position, {this.index});
}

class PlayerNext extends PlayerEvent {}
Expand Down
13 changes: 11 additions & 2 deletions lib/src/data/repositories/player_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract class JustAudioPlayer {
Future<void> play();
Future<void> pause();
Future<void> stop();
Future<void> seek(Duration position);
Future<void> seek(Duration position, {int? index});
Future<void> seekToNext();
Future<void> seekToPrevious();
Stream<Duration> get position;
Expand Down Expand Up @@ -144,7 +144,16 @@ class JustAudioPlayerImpl implements JustAudioPlayer {
Future<void> stop() => _player.stop();

@override
Future<void> seek(Duration position) => _player.seek(position);
Future<void> seek(Duration position, {int? index}) async {
if (index != null) {
await _player.seek(
position,
index: index,
);
} else {
await _player.seek(position);
}
}

@override
Future<void> seekToNext() => _player.seekToNext();
Expand Down
5 changes: 3 additions & 2 deletions lib/src/presentation/pages/about_page.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/core/constants/assets.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher_string.dart';

import 'package:meloplay/src/core/constants/assets.dart';
import 'package:meloplay/src/core/theme/themes.dart';

class AboutPage extends StatefulWidget {
const AboutPage({super.key});

Expand Down
89 changes: 6 additions & 83 deletions lib/src/presentation/pages/album_page.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import 'package:flutter/material.dart';
import 'package:marquee/marquee.dart';
import 'package:on_audio_query/on_audio_query.dart';

import 'package:meloplay/src/core/di/service_locator.dart';
import 'package:meloplay/src/core/extensions/string_extensions.dart';
import 'package:meloplay/src/core/helpers/helpers.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/presentation/widgets/player_bottom_app_bar.dart';
import 'package:meloplay/src/presentation/widgets/song_list_tile.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/core/di/service_locator.dart';
import 'package:on_audio_query/on_audio_query.dart';

class AlbumPage extends StatefulWidget {
final AlbumModel album;
Expand Down Expand Up @@ -151,88 +152,10 @@ class _AlbumPageState extends State<AlbumPage> {

// margin for bottom app bar
const SliverToBoxAdapter(
child: SizedBox(height: 80),
child: SizedBox(height: 60),
),
],
)
// Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// // back button
// Row(
// children: [
// IconButton(
// onPressed: () {
// Navigator.of(context).pop();
// },
// icon: const Icon(Icons.arrow_back_ios),
// ),
// ],
// ),
// // album artwork
// Expanded(
// child: QueryArtworkWidget(
// id: widget.album.id,
// type: ArtworkType.ALBUM,
// size: 10000,
// artworkWidth: double.infinity,
// artworkBorder: BorderRadius.circular(50),
// nullArtworkWidget: Container(
// width: double.infinity,
// decoration: BoxDecoration(
// color: Colors.grey.withOpacity(0.1),
// borderRadius: BorderRadius.circular(50),
// ),
// child: const Icon(
// Icons.music_note_outlined,
// size: 100,
// ),
// ),
// ),
// ),
// const SizedBox(height: 16),
// // album name
// Padding(
// padding: const EdgeInsets.symmetric(horizontal: 16),
// child: Text(
// widget.album.album,
// style: const TextStyle(
// fontSize: 24,
// fontWeight: FontWeight.bold,
// ),
// ),
// ),
// // artist name
// Padding(
// padding: const EdgeInsets.symmetric(horizontal: 16),
// child: Text(
// widget.album.artist ?? 'Unknown',
// style: const TextStyle(
// fontSize: 18,
// color: Colors.grey,
// ),
// ),
// ),
// const SizedBox(height: 16),
// // songs
// Expanded(
// child: ListView.builder(
// padding: EdgeInsets.zero,
// itemCount: _songs.length,
// itemBuilder: (context, index) {
// final SongModel song = _songs[index];

// return SongListTile(
// song: song,
// songs: _songs,
// showAlbumArt: false,
// );
// },
// ),
// ),
// ],
// ),
),
)),
);
}
}
4 changes: 2 additions & 2 deletions lib/src/presentation/pages/artist_page.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:marquee/marquee.dart';
import 'package:meloplay/src/core/helpers/helpers.dart';
import 'package:on_audio_query/on_audio_query.dart';

import 'package:meloplay/src/core/di/service_locator.dart';
import 'package:meloplay/src/core/extensions/string_extensions.dart';
import 'package:meloplay/src/core/helpers/helpers.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/presentation/widgets/player_bottom_app_bar.dart';
import 'package:meloplay/src/presentation/widgets/song_list_tile.dart';
Expand Down Expand Up @@ -151,7 +151,7 @@ class _ArtistPageState extends State<ArtistPage> {

// margin for bottom app bar
const SliverToBoxAdapter(
child: SizedBox(height: 80),
child: SizedBox(height: 60),
),
],
),
Expand Down
15 changes: 5 additions & 10 deletions lib/src/presentation/pages/favorites_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'package:meloplay/src/bloc/favorites/favorites_bloc.dart';
import 'package:meloplay/src/bloc/song/song_bloc.dart';
import 'package:meloplay/src/core/theme/themes.dart';
Expand Down Expand Up @@ -71,18 +72,12 @@ class _FavoritesPageState extends State<FavoritesPage> {
);
}
return ListView.builder(
padding: EdgeInsets.zero,
padding: const EdgeInsets.only(bottom: 60),
itemCount: state.favoriteSongs.length,
itemBuilder: (context, index) {
return Column(
children: [
SongListTile(
song: state.favoriteSongs[index],
songs: state.favoriteSongs,
),
if (index == state.favoriteSongs.length - 1)
const SizedBox(height: 80),
],
return SongListTile(
song: state.favoriteSongs[index],
songs: state.favoriteSongs,
);
},
);
Expand Down
9 changes: 6 additions & 3 deletions lib/src/presentation/pages/genre_page.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:on_audio_query/on_audio_query.dart';

import 'package:meloplay/src/core/di/service_locator.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/presentation/widgets/player_bottom_app_bar.dart';
import 'package:meloplay/src/presentation/widgets/song_list_tile.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/core/di/service_locator.dart';
import 'package:on_audio_query/on_audio_query.dart';

class GenrePage extends StatefulWidget {
final GenreModel genre;
Expand Down Expand Up @@ -71,6 +72,8 @@ class _GenrePageState extends State<GenrePage> {
},
),
),
// margin for bottom app bar
const SizedBox(height: 60),
],
),
),
Expand Down
2 changes: 1 addition & 1 deletion lib/src/presentation/pages/home/home_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
// current song, play/pause button, song progress bar, song queue button
bottomNavigationBar: const PlayerBottomAppBar(),
extendBody: true,
backgroundColor: Themes.getTheme().secondaryColor,
drawer: _buildDrawer(context),
appBar: _buildAppBar(),
body: _buildBody(context),
Expand Down Expand Up @@ -123,7 +124,6 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
actions: [
IconButton(
onPressed: () {
// TODO: implement search
Navigator.of(context).pushNamed(AppRouter.searchRoute);
},
icon: const Icon(Icons.search_outlined),
Expand Down
53 changes: 2 additions & 51 deletions lib/src/presentation/pages/player_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:just_audio/just_audio.dart';
import 'package:just_audio_background/just_audio_background.dart';
import 'package:meloplay/src/presentation/widgets/seek_bar.dart';
import 'package:on_audio_query/on_audio_query.dart';

import 'package:meloplay/src/bloc/player/player_bloc.dart';
Expand Down Expand Up @@ -171,57 +172,7 @@ class _PlayerPageState extends State<PlayerPage> {
const Spacer(),

// seek bar
StreamBuilder<Duration>(
stream: player.position,
builder: (context, snapshot) {
final position = snapshot.data ?? Duration.zero;
return StreamBuilder<Duration?>(
stream: player.duration,
builder: (context, snapshot) {
final duration = snapshot.data ?? Duration.zero;
return Column(
children: [
Slider(
value: position > duration
? duration.inMilliseconds.toDouble()
: position.inMilliseconds.toDouble(),
min: 0,
max: duration.inMilliseconds.toDouble(),
onChanged: (value) {
context.read<PlayerBloc>().add(
PlayerSeek(
Duration(milliseconds: value.toInt()),
),
);
},
),

// position and duration text
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'${position.inMinutes.toString().padLeft(2, '0')}:${(position.inSeconds % 60).toString().padLeft(2, '0')}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
'${duration.inMinutes.toString().padLeft(2, '0')}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
],
);
},
);
},
),
SeekBar(player: player),
const Spacer(),

Row(
Expand Down
3 changes: 2 additions & 1 deletion lib/src/presentation/pages/playlist_details_page.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:on_audio_query/on_audio_query.dart';

import 'package:meloplay/src/core/theme/themes.dart';

class PlaylistDetailsPage extends StatefulWidget {
final PlaylistModel playlist;
const PlaylistDetailsPage({super.key, required this.playlist});
Expand Down
3 changes: 2 additions & 1 deletion lib/src/presentation/pages/queue_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';

import 'package:meloplay/src/core/di/service_locator.dart';
import 'package:meloplay/src/core/theme/themes.dart';
import 'package:meloplay/src/data/repositories/player_repository.dart';
Expand Down Expand Up @@ -34,7 +35,7 @@ class _QueuePageState extends State<QueuePage> {
final playlist = sl<JustAudioPlayer>().playlist;

return ListView.builder(
padding: EdgeInsets.zero,
padding: const EdgeInsets.only(bottom: 60),
itemCount: playlist.length,
itemBuilder: (context, index) {
return SongListTile(
Expand Down
Loading

0 comments on commit ae9e28b

Please sign in to comment.