Android App Migration Guide

A detailed blueprint for rebuilding the Mediaverse web application as a native Android app using Kotlin or Java.

1. Project Intent & Core Purpose

Mediaverse is a digital media library aggregator. Its primary goal is to provide users with a single, unified interface to manage movie and TV show collections that are scattered across multiple digital retailers (like Fandango, Movies Anywhere, etc.). It addresses the problem of a fragmented digital library by consolidating media, enriching it with AI-powered metadata, and offering powerful tools for curation and discovery.

Core Objectives for the Android App:

  • Data Unification: Allow users to import their libraries via CSV files and merge them into a single, de-duplicated local database (e.g., using Room persistence library).
  • Rich UI/UX: Recreate the visual experience using native Android UI components (e.g., Jetpack Compose), focusing on a clean, card-based, and poster-driven interface.
  • AI Integration: Connect to the same AI backend (Genkit flows) via a REST API or a Firebase Cloud Functions layer to perform metadata enrichment, poster generation, and content curation.
  • Curation Tools: Implement "Bundles" (collections) with drag-and-drop reordering and AI-assisted creation.
  • Family Safety: Include a "Kids Mode" with robust filtering based on parental guidance ratings and standard movie/TV ratings.
  • Cloud Sync: Integrate with Google Sign-In and the Google Drive API to allow users to back up and restore their local app database.

2. Visual Design, Theming, and UI Components

The app's aesthetic is modern, dark, and media-centric. A native implementation should strive for a similar feel while adhering to Android design principles.

Color Palettes & Theming

The app supports multiple themes. These are defined by a set of core color values. In a native app, these would be defined in `colors.xml` or as a `ColorScheme` in Jetpack Compose for each theme.

Dark Theme (Default)
  • Background: Very dark blue/charcoal (`hsl(224 71.4% 4.1%)`)
  • Foreground (Text): Off-white (`hsl(210 20% 98%)`)
  • Primary (Accent): Muted purple/blue (`hsl(231 48% 48%)`)
  • Cards/Secondary Elements: Dark blue, slightly lighter than background (`hsl(215 27.9% 16.9%)`)
Red Carpet Theme
  • Background: Deep, dark red (`hsl(0 100% 4%)`)
  • Primary (Accent): Bright, bold red (`hsl(0 72% 51%)`)
  • Accent Foreground: Gold/Yellow (`hsl(48 89% 60%)`)

Typography

  • Primary Font: Inter. This can be included as a custom font resource in the Android project.
  • Headings: Bold weight. (e.g., `h1` is ~36sp, `h2` is ~24sp, `h3` is ~20sp).
  • Body Text: Regular weight. (~16sp).
  • Labels/Metadata: Medium weight, smaller size. (~14sp).
  • Colors: Use `foreground` for body text and `muted-foreground` (a lighter gray) for secondary info like years, ratings, etc.

3. Page-by-Page UI and Functionality Breakdown

3.1 Main Library & Discovery Page (`/`)

This is the home screen of the application. It's built around a Tabbed Layout with two primary sections: "Unified Library" and "Interactive Mode".

Unified Library Tab

Appearance:

A clean grid of movie/TV show posters. The primary focus is browsing the user's entire owned collection.

Components:

  • Search Bar: A text input field for filtering titles in real-time.
  • Media Type Tabs: Tabs for "All", "Movies", and "TV Series" to filter the grid.
  • Filter & Sort Controls: Collapsible sections containing dropdowns (Spinners in Android) for:
    • Filtering: By Genre, Rating, and Retailer. Each dropdown should be populated dynamically from the available media data.
    • Sorting: Two separate dropdowns for "Primary Sort" and "Secondary Sort". This allows for multi-level sorting (e.g., sort by Genre, then by Title). Sortable fields include Title, Rating, Runtime, Release Date, etc. An adjacent button toggles Ascending/Descending order for each.
  • Media Grid: An adaptive grid (`RecyclerView` or `LazyVerticalGrid` in Compose) displaying `MediaCard` components.

Functionality Notes:

The filtering and sorting logic must be combined. When any filter or sort option changes, the grid should update immediately. Unowned titles (items with no ownership records) should be explicitly excluded from this view.

Interactive Mode Tab

Appearance:

A more dynamic, discovery-oriented view. It features horizontally scrolling carousels.

Components:

  • Bundles Section: A grid of `BundleCard` components. This should be the first section, with a button to create a new bundle.
  • Genre Carousels: For each major genre (e.g., Action, Comedy, with at least 5 items), a horizontally scrolling carousel (`RecyclerView` or `LazyRow`) of `MediaCard` components is displayed.

Functionality Notes:

This view should also only display owned media items. It's designed to encourage rediscovery of the user's library.

3.2 Media Detail Page (`/media/[id]`)

This screen displays all information about a single Movie or TV Show.

Media Detail Layout & Components

Appearance:

A two-column layout on larger screens (tablets), and a single-column scrolling layout on phones. A large poster image is the focal point.

Key UI Elements:

  • Poster Image: Large, prominent artwork.
  • Title Block: Includes Title, Year, Rating, Runtime, and Type (Movie/TV).
  • Badges: Small, pill-shaped labels for Genre, Retailers (e.g., Fandango), and "Kid Friendly" status.
  • Description/Synopsis: A paragraph of text.
  • Action Buttons:
    • Play Button: Opens the deep link URL for the primary retailer. If multiple retailers are available, it becomes a split button with a dropdown to choose the retailer.
    • Add to Bundle: A dropdown to add the item to an existing bundle.
    • Edit Metadata: Opens a dialog/modal to override metadata fields.
  • AI Insights Section: A dedicated card with buttons to trigger AI functions:
    • Enrich with AI: Fetches comprehensive metadata.
    • Is this Kid Friendly?: A simple check against user settings.
    • Fetch Parental Guidance: Scrapes the web for detailed ratings.
    • Merge Duplicates: Allows merging this item with another from the library.
    • Find & Attach to Parent (Featurettes only): Links a "making of" documentary to its main film.
  • Content Sections: Conditional sections that appear only if data exists: Parental Guidance, Extra Content, Cast, Similar Titles, and Seasons/Episodes (for TV).

3.3 Bundle Detail Page (`/bundle/[id]`)

Manages the contents of a single user-created collection.

Bundle Detail Layout & Components

Appearance:

Similar to the media detail page, with a large poster for the bundle itself, followed by a grid of the media items it contains.

Key UI Elements:

  • Bundle Poster & Title: Displaying the collection's artwork and name.
  • Action Buttons:
    • Create Poster with AI: Generates a unique poster for the bundle.
    • Build Collection with AI: Opens a dialog to automatically add titles based on a text prompt. This can either search the user's library or the open web.
    • Remove Items: Enters a selection mode to remove multiple items from the bundle.
    • Delete Bundle: Deletes the entire collection (but not the media items themselves).
  • Media Grid: A grid of all items in the bundle. This is the only place (besides this page) where "Unowned" items are displayed. This grid must support drag-and-drop reordering.

3.4 Settings Pages (`/settings/*`)

A standard settings area with a navigation list on the left (or at the top on phones) and content on the right.

  • Retailers: Manage CSV imports and column mappings.
  • Kids Mode: Toggle the mode and configure all related parental controls.
  • API Keys: Input fields for TMDb, OMDb, and TheTVDB keys.
  • This Guide: The page you are currently reading.

4. Complex Component & Logic Implementation Details

Media Card Component
The core visual element of the library.

This is a reusable component for displaying a single media item's poster.

  • Poster Image: The background of the card. It should have a 2:3 aspect ratio.
  • Retailer Overlays: Small icons for each retailer where the item is owned are overlaid on the top-right corner of the poster. If an item is owned in more than one account from the same retailer (e.g., two Fandango accounts), a secondary icon appears on the bottom-left.
  • Unowned State: If an item has no ownership records, the poster should be displayed in grayscale with a diagonal red banner in the top-left corner that reads "Not Owned". This state is crucial for items within bundles.
  • Lazy Loading: Posters for items with placeholder URLs should be lazy-loaded. When the card scrolls into view, it should first attempt to find a matching poster from another item in the local database with the same title/year. If none is found, it should then make an API call to fetch a poster from an external service (TMDb/OMDb).
  • Title/Year: Displayed below the poster.
Data Ingestion and TV Show Grouping
Logic for handling CSV imports and data merging.

This is a critical background process that must be replicated carefully.

  1. Parsing: Use a robust CSV parsing library.
  2. Column Mapping: The user must be able to map CSV columns to the app's internal data fields (Title, Year, Genre, etc.). This mapping should be saved per account.
  3. De-duplication: When new items are imported, the system must check against the existing database. A match is determined by a normalized title (lowercase, punctuation/symbols removed) and a release year (allowing for a +/- 1 year tolerance for movies). If a match is found, the ownership data is merged into the existing record.
  4. TV Series Aggregation:
    • The system must use regular expressions to parse titles like "Show Name: Season 1: Episode Title" or "Show Name: Season 1".
    • When an item is identified as a TV episode or season, the logic should find or create a single parent "TV Show" entity.
    • All episodes from the same season are grouped under a `Season` object. Seasons are then collected under the parent `TV Show` object.
    • Seasons should be sorted chronologically by year or season number.
  5. Featurette Handling: Titles ending in `(featurette)` are treated specially. The logic attempts to parse the parent movie title from the featurette's title (e.g., "Movie Name - Making Of (featurette)"). It then finds the parent movie in the database and attaches the featurette as `ExtraContent`, removing it from the main library view.
Kids Mode & Parental Controls
Implementing the content filtering logic.

This is a multi-layered filter applied to all library views when enabled.

  1. Manual Override: A per-item boolean flag (`isKidFriendly`) can be manually set to `true` or `false`, which always takes highest priority.
  2. Parental Guidance Ratings: On the settings page, users can set sliders (0-10) for Sex, Violence, and Language. If a media item has this detailed guidance data, it is only shown if its scores are at or below ALL three user settings.
  3. Standard Ratings Fallback: If no detailed guidance exists, the system falls back to standard ratings (G, PG, PG-13, etc.). The user can select which ratings are permissible in the settings.
  4. Sensitive Content Password: A separate, app-wide password can be set. Any media item can be manually flagged as `sensitive`. To view the detail page for a sensitive item, the user must enter this password, regardless of whether Kids Mode is on or off.
Data Storage & Cloud Sync
Handling local data and Google Drive backup.

Local Storage:

The entire application state should be persisted in a local database on the device (e.g., Room). This includes:

  • All media items, including TV show structures.
  • All user-created bundles and their item order.
  • All user settings (Kids Mode, API keys, Retailer account info, column mappings).
  • The content of imported CSV files should also be stored to allow for "Rescanning".

Cloud Sync (Google Drive):

  • The app must integrate with Google Sign-In and request the `drive.file` scope.
  • On "Save", the entire local database should be serialized into a single JSON file.
  • This JSON file is then uploaded to the user's Google Drive in a special, hidden "appDataFolder" to keep it from cluttering their main Drive view.
  • On "Load", the app downloads this JSON file, completely overwrites the local database with its contents, and then restarts or reloads to reflect the new state.