Skip to content

3.3 Modal System

ankrypht edited this page Jul 16, 2025 · 1 revision

Page: Modal System

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.

Modal Architecture Overview

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.

Modal Presentation Patterns

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
Loading

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

Core Modal Components

Queue Management

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
Loading

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

Playlist Management Modals

AddToPlaylistModal

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

CreatePlaylistModal

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
Loading

The component validates input using playlistName.trim() and shows error messages via ToastAndroid for empty names.

Sources: app/(modals)/createPlaylist.tsx:39-97

System Notification Modals

UpdateModal

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
Loading

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

MessageModal

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

Modal Navigation Patterns

VerticalDismiss Component

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
Loading

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

Modal Styling Patterns

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

Clone this wiki locally