Building A Watchlist Screen For Your Anime App
Hey guys! Let's dive into building a new screen for your anime app. This screen will help you keep track of what you're currently watching, making it super easy to manage your anime journey. We'll be pulling data, implementing filters, and adding some cool features to make it awesome. Ready?
Screen Overview
We're adding a new screen to manage what you're watching. This will include shows that are currently airing, as well as older shows that don't have a set broadcast schedule. This will help you keep track of your progress and manage all of your currently watching anime. Let's check out the main parts:
Main Menu Updates
The main menu, also known as the drawer menu, will have these changes:
- Broadcast Schedule: Renamed from "Track" screen to make things clearer.
- Watching: This is the new screen we're building!
- History: This might be renamed from the "History" screen. We'll need to confirm the name. The name can be discussed later on.
- Settings: This stays the same.
Watching Screen: Features
Let's break down what we'll need for this new screen. We'll look at where the data comes from, how to filter and sort it, and how to display it nicely. We are going to display it in a card view style!
Data Sources
- API: We'll use the
viewer.libraryEntries(states: [WATCHING])
from the API to get the data. - Data We'll Get: We'll grab the following details:
- Anime Info: Title, season, year, and media type.
- Next Episode: Episode number, title, and display text.
- Images: We'll use
recommendedImageUrl
orfacebookOgImageUrl
for the visuals.
Filtering Options
- Radio Buttons:
[Past Shows Only ✓]
(Default): Shows only shows not available inviewer.programs
.[All Shows]
: Shows all anime currently being watched, including airing anime.
- Existing Filters: We'll reuse filters for season, year, and media type.
Sorting the List
- Sort by the last watched date and time (newest first): We will need to confirm if this is possible using the Annict API (
libraryEntries.updatedAt
).
How the Cards Look
Here's how each anime card will be displayed:
┌─────────────────────────────────┐
│ 📺 [Image] Heavenly Delusion │
│ Spring 2023 TV │
│ Next: Episode 9 │
│ "Children of the Academy" │
│ 📍 Netflix │
└─────────────────────────────────┘
What Happens When You Tap
- Tapping a Card: Takes you to the
AnimeDetailScreen
. - Data Structure: We'll pass data using a structure like
ProgramWithWork
, which is a similar new structure toLibraryEntryWithWork
.
Episode Tracking (Local Database)
Let's talk about how we'll handle episode counts. This can get tricky, so let's go through the issues and how we can solve them. We will solve them step by step!
Challenges
- Annict Data: The
episodesCount
in Annict isn't always final before a show finishes. - MyAnimeList Data: While
num_episodes
in MyAnimeList is accurate, getting all the data for all shows can put a lot of stress on the API.
The Solution: Gradual Information Updates
Here's our plan for getting the episode counts right:
【First time loading - list screen】
Heavenly Delusion: Next 9/? (Unconfirmed) ← Annict episodesCount
Fruits Basket: Next 4/12 ← Annict episodesCount (Finished airing)
【Go to detail screen】
→ Get num_episodes=13 from MyAnimeList API
→ Save to local database: { workId, episodeCount: 13, source: "MAL" }
【Go back to list screen】
Heavenly Delusion: Next 9/13 ← Get from DB (Unconfirmed disappears)
How It Works
- List Screen: We'll show Annict's
episodesCount
. - "Unconfirmed" Label: We'll add "(Unconfirmed)" if the show hasn't finished airing.
- Detail Screen: When we get data from MyAnimeList, we'll save it to the database.
- List Screen Priority: The list screen will use the database first, then Annict.
Platform Management
It can be tricky to remember where you're watching each anime, so this feature will help a lot.
The Goal
- Let users set the platform where they're watching each show.
User Interface (Option A: In a Modal)
This is how we can design the UI in the modal:
Rename: Rename DetailModal
to EpisodeRecordModal
.
Add a new feature for "Watching" screen: Platform setting UI.
┌─────────────────────────────────┐
│ Watching Platform │
├─────────────────────────────────┤
│ ⚪ Netflix │
│ ⚪ Amazon Prime Video │
│ ⚪ Disney+ │
│ ⚪ U-NEXT │
│ ● dAnime Store │
│ ⚪ Not set │
│ │
│ ┌─────────────────────────┐ │
│ │ + Custom Platform │ │
│ │ [Text Input] │ │
│ │ [Add Button] │ │
│ └─────────────────────────┘ │
└─────────────────────────────────┘
Where Platforms Come From
- Annict: Get from
work.programs.channel
. - Custom: Users can add their own platforms (manage this in the settings).
- Not Set: The default state.
Implementation Details
@Composable
fun PlatformSelector(
selectedPlatform: String?,
platforms: List<String>, // Annict + custom
onSelect: (String?) -> Unit,
onAddCustom: (String) -> Unit
) {
Column {
// Radio button list
platforms.forEach { platform ->
RadioButton(...)
}
// Custom addition (collapsible)
var showCustomInput by remember { mutableStateOf(false) }
if (showCustomInput) {
OutlinedTextField(...)
Button("Add") { onAddCustom(...) }
} else {
TextButton("+ Add Custom Platform") {
showCustomInput = true
}
}
}
}
Local Database Design (Room)
We'll use Room for our local database. Here are the tables we'll need:
1. work_episode_cache (Episode Count Cache)
@Entity(tableName = "work_episode_cache")
data class WorkEpisodeCache(
@PrimaryKey val workId: String,
val episodeCount: Int,
val source: String, // "ANNICT" or "MAL"
val updatedAt: Long
)
2. work_platform_preferences (Platform Settings)
@Entity(tableName = "work_platform_preferences")
data class WorkPlatformPreference(
@PrimaryKey val workId: String,
val platformName: String?, // null = Not set
val updatedAt: Long
)
3. custom_platforms (Custom Platforms)
@Entity(tableName = "custom_platforms")
data class CustomPlatform(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val name: String,
val createdAt: Long
)
Task List (Estimated)
Here's a rough idea of what we need to do:
- Rename: Rename "Track" screen to "Broadcast Schedule".
- Rename (Check): Rename "History" screen to "Record History".
- Rename: Rename DetailModal to
EpisodeRecordModal
. - GraphQL Query: Add the
viewer.libraryEntries
query. - Implement: Implement the Repository/UseCase.
- Implement: Implement the ViewModel.
- UI: Build the UI for the "Watching" screen.
- Radio button filters
- Card display
- Sorting
- UI: Implement the platform settings UI.
EpisodeRecordModal
changes- Radio button selection
- Custom addition UI (collapsible)
- Local Database: Implement the local database (Room).
- Entity definitions
- DAO implementation
- Migration
- Episode Count Logic: Implement episode count logic.
- Database priority display
- Update the database after getting data from MAL.
- Logic for "(Unconfirmed)" label
- Navigation: Add navigation.
- Testing: Implement tests.
- UnitTest
- IntegrationTest
- UITest
Important Notes
- We'll start implementing this after the
AnimeDetailScreen
is reviewed and merged. - We need to check if we can get the last watched date and time from the Annict API.
- We need to figure out how to determine if a show has finished airing (e.g., checking the
work.status
field).
I hope you enjoyed this article. If you want to learn more about this topic, I recommend checking out this website: MyAnimeList.