-
Notifications
You must be signed in to change notification settings - Fork 12
3.3 Modal System
Relevant source files
The following files were used as context for generating this wiki page:
This document covers the modal presentation system in AudioScape, detailing the various modal components used throughout the application for user interactions such as playlist management, queue viewing, and system notifications. The modal system provides overlay interfaces that appear on top of the main application content.
For information about the main player interface, see Player Interface. For details about the primary navigation screens, see Tab Navigation Screens.
AudioScape implements a layered modal system built on React Native's navigation and modal capabilities. The system uses both expo-router modal routes and standalone Modal components for different use cases.
graph TB
subgraph "App Navigation Stack"
ROOT["RootLayout"]
TABS["(tabs) - Main Tab Container"]
MODALS["Modal Routes Group"]
end
subgraph "Route-Based Modals"
ADD_PLAYLIST["app/(modals)/addToPlaylist.tsx<br/>AddToPlaylistModal"]
QUEUE["app/(modals)/queue.tsx<br/>QueueModal"]
CREATE_PLAYLIST_ROUTE["app/(modals)/createPlaylist.tsx<br/>CreatePlaylistModal"]
PLAYER["app/player.tsx<br/>PlayerScreen"]
end
subgraph "Component-Based Modals"
UPDATE_MODAL["components/UpdateModal.tsx<br/>UpdateModal"]
MESSAGE_MODAL["components/MessageModal.tsx<br/>MessageModal"]
CREATE_PLAYLIST_COMP["CreatePlaylistModal Component"]
end
subgraph "Navigation Utilities"
VERTICAL_DISMISS["components/navigation/VerticalArrowDismiss<br/>VerticalDismiss"]
end
ROOT --> TABS
ROOT --> MODALS
MODALS --> ADD_PLAYLIST
MODALS --> QUEUE
MODALS --> CREATE_PLAYLIST_ROUTE
MODALS --> PLAYER
ADD_PLAYLIST --> CREATE_PLAYLIST_COMP
ADD_PLAYLIST --> VERTICAL_DISMISS
QUEUE --> VERTICAL_DISMISS
TABS -.->|"Overlay"| UPDATE_MODAL
TABS -.->|"Overlay"| MESSAGE_MODAL
style ROOT fill:#f9f9f9
style MODALS fill:#e8f5e8
style VERTICAL_DISMISS fill:#fff3e0
Sources: app/(modals)/addToPlaylist.tsx:1-240, app/(modals)/queue.tsx:1-293, app/(modals)/createPlaylist.tsx:1-159, components/UpdateModal.tsx:1-197, components/MessageModal.tsx:1-169
The QueueModal displays the current music playback queue and allows users to navigate between tracks.
graph LR
subgraph "QueueModal Implementation"
QUEUE_COMPONENT["QueueModal<br/>app/(modals)/queue.tsx"]
TRACK_PLAYER["TrackPlayer"]
ACTIVE_TRACK["useActiveTrack"]
ROUTER["useRouter"]
end
subgraph "Key Functions"
FETCH_QUEUE["fetchQueue()"]
HANDLE_SONG_SELECT["handleSongSelect()"]
RENDER_SONG_ITEM["renderSongItem()"]
end
subgraph "State Management"
QUEUE_STATE["queue: Track[]"]
ACTIVE_INDEX["activeIndex: number"]
IS_SCROLLING["isScrolling: boolean"]
end
subgraph "UI Components"
FLAT_LIST["FlatList"]
VERTICAL_DISMISS["VerticalDismiss"]
LOADER_KIT["LoaderKit indicator"]
end
QUEUE_COMPONENT --> FETCH_QUEUE
QUEUE_COMPONENT --> HANDLE_SONG_SELECT
QUEUE_COMPONENT --> RENDER_SONG_ITEM
FETCH_QUEUE --> TRACK_PLAYER
HANDLE_SONG_SELECT --> TRACK_PLAYER
QUEUE_COMPONENT --> QUEUE_STATE
QUEUE_COMPONENT --> ACTIVE_INDEX
QUEUE_COMPONENT --> IS_SCROLLING
RENDER_SONG_ITEM --> FLAT_LIST
QUEUE_COMPONENT --> VERTICAL_DISMISS
RENDER_SONG_ITEM --> LOADER_KIT
HANDLE_SONG_SELECT --> ROUTER
The modal fetches queue data using TrackPlayer.getQueue() and TrackPlayer.getActiveTrackIndex(), polling every 2 seconds for updates. Users can skip to any track by calling TrackPlayer.skip().
Sources: app/(modals)/queue.tsx:33-212
The AddToPlaylistModal allows adding the current or selected track to existing playlists or creating new ones.
| Component | Purpose | Key Dependencies |
|---|---|---|
AddToPlaylistModal |
Main playlist selection interface |
usePlaylists, useActiveTrack
|
CreatePlaylistModal |
New playlist creation form | React Native Modal |
VerticalDismiss |
Swipe-to-dismiss navigation | Custom navigation component |
The modal converts the playlists object into an array for FlatList rendering and handles track data from either navigation params or the active track.
Sources: app/(modals)/addToPlaylist.tsx:37-177
graph TB
subgraph "CreatePlaylistModal Interface"
MODAL["Modal Container"]
TEXT_INPUT["TextInput<br/>playlistName"]
BUTTONS["Action Buttons"]
end
subgraph "Props Interface"
VISIBLE["visible: boolean"]
ON_CREATE["onCreate: (name: string) => void"]
ON_CANCEL["onCancel: () => void"]
end
subgraph "Validation Flow"
HANDLE_CREATE["handleCreate()"]
VALIDATE["playlistName.trim() check"]
TOAST["ToastAndroid.show()"]
CLEAR_INPUT["setPlaylistName('')"]
end
MODAL --> TEXT_INPUT
MODAL --> BUTTONS
VISIBLE --> MODAL
ON_CREATE --> HANDLE_CREATE
ON_CANCEL --> BUTTONS
HANDLE_CREATE --> VALIDATE
VALIDATE --> TOAST
VALIDATE --> ON_CREATE
ON_CREATE --> CLEAR_INPUT
The component validates input using playlistName.trim() and shows error messages via ToastAndroid for empty names.
Sources: app/(modals)/createPlaylist.tsx:39-97
The UpdateModal checks for app updates by fetching release data from the GitHub API and comparing versions.
graph LR
subgraph "Update Check Flow"
FETCH_MESSAGE["fetchMessage()"]
GITHUB_API["GitHub API<br/>releases/latest"]
COMPARE_VERSIONS["compareVersions()"]
APPLICATION_VERSION["Application.nativeApplicationVersion"]
end
subgraph "Version Comparison"
NORMALIZE["normalizeVersion()"]
MAJOR_MINOR_PATCH["major.minor.patch parsing"]
VERSION_RESULT["1: newer, -1: older, 0: equal"]
end
subgraph "Modal State"
IS_MODAL_VISIBLE["isModalVisible"]
IS_UP_TO_DATE["isUpToDate"]
MESSAGE_STATE["message: string"]
end
FETCH_MESSAGE --> GITHUB_API
GITHUB_API --> COMPARE_VERSIONS
COMPARE_VERSIONS --> APPLICATION_VERSION
COMPARE_VERSIONS --> NORMALIZE
NORMALIZE --> MAJOR_MINOR_PATCH
MAJOR_MINOR_PATCH --> VERSION_RESULT
VERSION_RESULT --> IS_MODAL_VISIBLE
VERSION_RESULT --> IS_UP_TO_DATE
GITHUB_API --> MESSAGE_STATE
The modal uses expo-application to get the current version and fetches from https://api.github.com/repos/ankrypht/AudioScape/releases/latest.
Sources: components/UpdateModal.tsx:19-149, components/UpdateModal.tsx:50-94
The MessageModal displays dynamic messages from Firebase Firestore with support for one-time display and clickable links.
The component fetches from the appData/activeMessage document and uses MMKV storage to track seen messages via lastSeenMessageId.
Sources: components/MessageModal.tsx:36-121
Most route-based modals use the VerticalDismiss component for consistent dismiss behavior:
graph TB
subgraph "VerticalDismiss Pattern"
WRAPPER["VerticalDismiss Wrapper"]
HANDLE_DISMISS["handleDismiss function"]
MODAL_CONTENT["Modal Content"]
DISMISS_BUTTON["Dismiss Button"]
end
subgraph "Usage Pattern"
QUEUE_USAGE["QueueModal usage"]
PLAYLIST_USAGE["AddToPlaylistModal usage"]
CHEVRON_DOWN["Entypo chevron-down icon"]
end
WRAPPER --> HANDLE_DISMISS
HANDLE_DISMISS --> MODAL_CONTENT
MODAL_CONTENT --> DISMISS_BUTTON
QUEUE_USAGE --> WRAPPER
PLAYLIST_USAGE --> WRAPPER
DISMISS_BUTTON --> CHEVRON_DOWN
Both QueueModal and AddToPlaylistModal implement this pattern with the Entypo chevron-down icon for dismissal.
Sources: app/(modals)/queue.tsx:158-211, app/(modals)/addToPlaylist.tsx:110-176
All modals follow consistent styling patterns using react-native-size-matters/extend for responsive scaling:
| Style Property | Common Values | Purpose |
|---|---|---|
modalOverlay |
backgroundColor: "rgba(0, 0, 0, 0)" |
Transparent background |
modalContent |
backgroundColor: "#101010" |
Dark theme consistency |
borderTopRadius |
"25@ms" |
Rounded top corners |
maxHeight |
"60%" |
Screen space management |
Sources: app/(modals)/queue.tsx:215-292, app/(modals)/addToPlaylist.tsx:180-239, app/(modals)/createPlaylist.tsx:102-159