A modern React Native music streaming application built with Expo, featuring a clean UI and seamless playback experience powered by Saavn API.
- 🎵 Music Playback: Stream songs with play, pause, skip controls
- 🔍 Search: Search for songs and artists with debounced search
- 👤 Artist Pages: Browse artist profiles with songs and albums
- 📋 Queue Management: Add songs to queue with simple tap interface
- 🎨 Theme Support: Light, Dark, and System theme modes
- 💾 Persistence: Recently played songs and queue saved locally
- 🎯 Mini Player: Floating mini player above bottom tabs
- 📱 Native Feel: Smooth animations and gestures
- React Native 0.81.5 - Mobile framework
- Expo ~54 - Development platform
- TypeScript 5.9 - Type safety
- React Navigation - Navigation library
- Native Stack Navigator
- Bottom Tabs Navigator
- twrnc - Tailwind CSS for React Native
- @expo/vector-icons - Icon library (Ionicons)
- react-native-safe-area-context - Safe area handling
- Zustand - Lightweight state management
- AsyncStorage - Local persistence
- expo-av - Audio playback
- Saavn API - Music streaming backend
- Node.js (v16 or higher)
- npm or yarn
- Expo CLI
- For iOS: macOS with Xcode
- For Android: Android Studio and SDK
- Clone the repository
git clone <repository-url>
cd Mmedia- Install dependencies
npm install- Start the development server
npx expo start- Run on device/simulator
For Android:
npx expo run:androidFor iOS:
npx expo run:iosThe project was initialized with:
npx create-expo-app Mmedia --template blank-typescript
npm i twrnc
npm i zustand
npm install @react-navigation/native-stack
npm install @react-navigation/elements
npm install @react-navigation/bottom-tabs
npm install @expo/vector-icons
npm install @react-native-async-storage/async-storage
npm install expo-avMmedia/
├── src/
│ ├── api/ # API services
│ │ └── saavn.ts # Saavn API integration
│ ├── audio/ # Audio playback
│ │ └── audioService.ts # Expo AV wrapper
│ ├── components/ # Reusable components
│ │ ├── BottomTabBar.tsx
│ │ ├── Header.tsx
│ │ ├── HorizontalList.tsx
│ │ ├── MiniPlayer.tsx # Floating mini player
│ │ ├── Section.tsx
│ │ ├── SongRow.tsx # Song list item with menu
│ │ └── Tabs.tsx
│ ├── navigation/ # Navigation setup
│ │ ├── AppNavigator.tsx
│ │ ├── BottomTabs.tsx # Tab navigation
│ │ └── types.ts # Navigation types
│ ├── screens/ # Screen components
│ │ ├── Artist/
│ │ │ ├── ArtistDetailScreen.tsx
│ │ │ └── ArtistsListScreen.tsx
│ │ ├── Favorites/
│ │ ├── Home/
│ │ │ ├── HomeScreen.tsx
│ │ │ ├── ArtistsTab.tsx
│ │ │ ├── SongsTab.tsx
│ │ │ ├── SuggestedSongs.tsx
│ │ │ └── SuggestedTab.tsx
│ │ ├── Player/
│ │ │ └── PlayerScreen.tsx
│ │ ├── Playlists/
│ │ ├── Queue/
│ │ │ └── QueueScreen.tsx
│ │ ├── Search/
│ │ │ └── SearchScreen.tsx
│ │ ├── SeeAll/
│ │ │ └── SongListScreen.tsx
│ │ └── Settings/
│ │ └── SettingsScreen.tsx
│ ├── storage/ # Storage utilities
│ │ └── playerStorage.ts
│ ├── store/ # State management
│ │ └── songStore.ts # Zustand store
│ ├── theme/ # Theming
│ │ ├── colors.ts
│ │ └── ThemeContext.tsx
│ └── utils/ # Helper functions
│ ├── getAudioUrl.ts
│ ├── getImage.ts
│ └── songHelpers.ts
├── App.tsx # App entry point
├── index.ts # Root entry
└── package.json
// Centralized store in src/store/songStore.ts
interface SongState {
songs: Song[]; // Current song list
currentSong: Song | null; // Now playing
isPlaying: boolean; // Playback state
queue: Song[]; // Queue management
recentlyPlayed: Song[]; // History
// ... actions
}Features:
- Global state for player, songs, and queue
- AsyncStorage integration for persistence
- Actions for play, pause, skip, queue management
BottomTabs (Main)
├── Home (Stack)
│ ├── HomeMain
│ ├── Player (Modal)
│ ├── Queue
│ ├── Search
│ ├── ArtistDetail
│ ├── ArtistsList
│ └── SongList
├── Favorites
├── Playlists
└── Settings
Custom Tab Bar:
- Floating mini player above tabs
- Hides on Player screen
- Gesture-friendly design
SongRow Component:
- Reusable song list item
- 3-dot menu for actions
- Modal-based menu UI
- Play/pause state indication
MiniPlayer:
- Floating above content
- Absolute positioning with shadow
- Tap to open full player
- Shows current song and controls
ThemeContext provides:
- Light/Dark/System modes
- System theme detection
- Persistent theme selection
- Dynamic color valuesBase URL: https://saavn.sumit.co/api
Endpoints:
searchSongs- Search songssearchArtists- Search artistsgetSongById- Get song detailsgetArtistById- Get artist infogetArtistSongs- Get artist's songsgetSongSuggestions- Get related songs
// Wrapper in src/audio/audioService.ts
-playSound(url) -
pauseSound() -
resumeSound() -
seekTo(position) -
setOnPlaybackStatusUpdate(callback);Features:
- Single audio instance management
- Playback status updates
- Auto-play next on finish
- Position tracking
User Action → Component → Store Action → API (if needed)
↓
Update State
↓
Persist to Storage
↓
Re-render Components
Example: Playing a song
- User taps SongRow
- Calls
setCurrentSong(song) - Store fetches audio URL
- Loads audio with expo-av
- Updates state (isPlaying: true)
- Saves to AsyncStorage
- UI updates (mini player, player screen)
AsyncStorage Keys:
lastPlayedSong- Last played song and indexrecentlyPlayed- Array of recent songs (max 10)queue- Current queue- App hydrates on startup
- Simple add/remove operations
- No drag-and-drop complexity
- Plays queue first, then song list
- Persisted locally
- Modal menu for adding songs
- 500ms debounce
- Real-time results
- Updates store for playback
- Clean empty state
- Light/Dark/System modes
- OS-level detection with
useColorScheme - Persisted selection
- Smooth transitions
- Floating design with shadow
- Positioned 60px above tabs
- Rounded corners
- Tap to expand
- Auto-hide on Player screen
Using twrnc (Tailwind CSS):
// Inline styles with theme
style={[
tw`flex-row items-center px-4`,
{ backgroundColor: theme.card }
]}
// Common patterns
tw`text-lg font-bold` // Typography
tw`px-4 py-3` // Spacing
tw`rounded-lg shadow-md` // Visual effects
tw`flex-1` // Flex layout- Create screen component in
src/screens/[Category]/ - Add route type in
src/navigation/types.ts - Register in navigator (
BottomTabs.tsxor stack) - Use theme context for colors
- Follow naming convention:
[Name]Screen.tsx
- Add state property to interface
- Initialize in store creation
- Create actions to modify state
- Add persistence if needed
- Export for component use
- Add endpoint function in
src/api/saavn.ts - Use TypeScript interfaces for responses
- Handle loading and error states
- Update store if needed for playback
Metro bundler issues:
npx expo start -cBuild errors:
npx expo prebuild --clean
npx expo run:androidAudio not playing:
- Check internet connection
- Verify Saavn API is accessible
- Check audio URL extraction
State not persisting:
- Verify AsyncStorage is installed
- Check hydration functions are called
- Clear app data and restart
- Favorites/Like functionality
- Playlists management
- Download for offline playback
- Lyrics display
- Social sharing
- Music recommendations
- Crossfade between songs
- Sleep timer
- Equalizer
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License.
- Saavn API for music streaming
- Expo team for excellent development tools
- React Navigation for routing solution
- All open-source contributors