📺 An Android app that allows you to track the anime you’ve watched with a simple interface, view comprehensive reports based on your watch history, and swipe to find your next favorite anime.
⬇️ Download from Google Play: https://play.google.com/store/apps/details?id=com.kc.myanimereport
anime_report_demo_final.mp4
Login/Signup | Home |
---|---|
Add/Edit/Delete Entry | Report |
---|---|
Match | Backlog |
---|---|
Anime Report allows you to track the anime you’ve watched with a simple interface, view comprehensive reports based on your watch history, and swipe to find your next favorite anime. Users can login/signup, add/edit/delete entries (each entry consists of an anime title, watch date, user rating, and optional note), view/share autogenerated reports with interactive and animated charts, be recommended a list of unseen animes (based on Slope One Collaborative Filtering and K-Nearest Neighbors), swipe or click buttons to accept/reject recommended animes, and manage a backlog of accepted animes.
This app uses Parse as its backend and utilizes the AniList GraphQL API. It also uses a number of third-party libraries, including Glide, MPAndroidChart, and CardStackView.
Slope One predicts the user's ratings of unseen animes based on other users' ratings of pairs of animes. However, it doesn't consider the similarity relationships among users. Therefore, I combined Slope One with K-Nearest Neighbors to find similar users, increased their weights, and improved the prediction accuracy. Click here to read more about my process of building the recommender.
I watch lots of anime, but I don't use an app to track them because existing apps such as MyAniList are overly complicated (unintuitive with too many status categories). I also like viewing a report based on my watch history with nice charts and graphs. Currently I'm tracking my list with a Google spreadsheet, set up my own report auto-generation with Data Studio, and I want to transfer this idea to an app. In addition, I hope to have an AI recommendation feature.
- Category: Utilities
- Mobile: Mobile-first experience, especially for the swipe gesture.
- Story: Users track the animes they've watched in a card-based layout, view autogenerated reports, and find new anime matches.
- Market: Anyone who watches anime could enjoy this app.
- Habit: Users can form a habit to track the animes they've watched. The match feature (rather than a discover feature) could help them find their next favorite anime without reading about too many animes that do not suit their interests. Even though the UI/UX is designed for simplicity, the autogenerated reports are comprehensive and insightful.
- Scope: V1 allows the user track what they've watched, view their trend report, share their report, and be matched with new animes. V2 could allow them to follow other users. The scope is currently limited to the anime industry, but can be adapted to other categories like dramas, TV shows, or even music.
Required Must-have Stories
- User can create a new account
- User can login/logout
- User can navigate between 4 tabs (Home, Report, Match, Backlog)
- User can see a list of entries in a card-based layout in the Home tab
- An entry consists of the anime's title, when the user watched it, the user's rating, and an optional reflective note
- User can add/edit/delete an entry from the Home tab
- User can view an entry's details in the Home tab
- User can view an anime's details in the Home and Match tabs
- User can view their report with informational charts and graphs, including
- An overview section
- Activity (line chart of time versus animes watched)
- Genre breakdown (pie chart)
- Genre preference (bar chart of genre versus average rating)
- Genre breakdown by year (stacked bar chart of year versus animes watched, broken down into genres)
- Their top-5 animes
- User can be matched with new animes based on their watch history
- User can swipe right or left to accept or reject an anime
- Accepted animes are added to the user's backlog
- User can view their backlog and delete animes from their backlog
Optional Nice-to-have Stories
- User can share their trend report to social media
- An entry's background color is the anime poster's primary color
- User can toggle between grid layout and list layout when viewing entries
- User can sort their entries in different ways (by rating, title, or chronological, descending or ascending)
- Use coordinator layout for fancier scrolling effects
- User can change their name and password
- User can delete all entries or all backlog animes at once
- User can click a backlog anime to view its details
- User can swipe left to delete a backlog item
- User can swipe right to add a backlog item as an entry
- User can filter entries by genre
- User can filter entries by anime title
- User can sign up with email verification
- Implement "forgot password"
- User can rewind a rejected anime
- User can sort backlog animes by date added (descending or ascending)
- User can filter backlog animes by title
- More sophisticated matching algorithm
- Login screen
- User can login
- Implement "forgot password"
- Registration screen
- User can sign up with email verification
- Home screen (tab 1)
- User can see a list of entries in a card-based layout
- User can filter entries by anime title
- Report sreen (tab 2)
- User can view their report with informational charts and graphs
- User can share their trend report to social media
- Match screen (tab 3)
- User can be matched with new animes based on their watch history
- User can swipe right or left to accept or reject an anime
- User can rewind a rejected anime
- Backlog screen (tab 4)
- User can view their accepted animes
- User can click a backlog anime to view its details
- User can swipe left to delete a backlog item
- User can swipe right to add a backlog item as an entry
- User can filter backlog animes by title
- Navigation drawer
- User can change their name and password
- User can logout
- User can toggle between grid layout and list layout when viewing entries
- User can sort their entries in different ways (by rating, title, or chronological, descending or ascending)
- User can delete all entries or all backlog animes at once
- User can filter entries by genre
- User can sort backlog animes by date added (descending or ascending)
- Entry creation screen
- User can add/edit an entry
- Entry detail screen
- User can view an entry's details
- User can delete an entry
- Anime detail screen
- User can view an anime's details
Tab Navigation (Tab to Screen)
- Home
- Report
- Match
- Backlog
Flow Navigation (Screen to Screen)
- Login screen
- -> Registration
- -> Home
- Registration screen
- -> Login
- -> Home
- Home screen
- -> Entry creation
- -> Entry detail
- -> Navigation drawer
- Report screen
- -> Navigation drawer
- Match screen
- -> Navigation drawer
- Backlog screen
- -> Entry creation
- -> Anime detail
- -> Navigation drawer
- Entry creation screen
- -> Home
- Entry detail screen
- -> Anime detail
- -> Home
- Anime detail screen
- -> Entry detail
- -> Backlog
Anime (a Media object from the AniList API)
Property | Type | Description |
---|---|---|
mediaId | Integer | Unique id for the anime in the AniList database |
titleEnglish | String | The official English title |
titleRomaji | String | Romanization of the native language title |
titleNative | String | Official title in its native language |
description | String | Short description of the media’s story and characters |
averageScore | Double | A weighted average score of all the user’s scores of the media |
seasonYear | Integer | The season year the media was initially released in |
coverImage | String | URL of the cover image of the media |
bannerImage | String | URL of the banner image of the media |
genres | List<String> | List of genres of the media |
color | String | Primary color of the cover image |
episodes | Integer | Number of episodes |
siteUrl | String | Url to AniList site |
Entry (Parse model)
Property | Type | Description |
---|---|---|
objectId | String | Unique id for the entry (default field) |
createdAt | Date | Date when entry is created (default field) |
updatedAt | Date | Date when entry is last updated (default field) |
user | Pointer | Pointer to the ParseUser who created the entry |
mediaId | Number | The AniList mediaId of the anime watched |
monthWatched | Number | The month when the user watched the anime |
yearWatched | Number | The year when the user watched the anime |
rating | Number | The user's rating of the anime (out of 10) |
note | String | An optinal reflective note on the anime |
BacklogItem (Parse model)
Property | Type | Description |
---|---|---|
objectId | String | Unique id for the entry (default field) |
createdAt | Date | Date when entry is created (default field) |
updatedAt | Date | Date when entry is last updated (default field) |
user | Pointer | Pointer to the ParseUser who created the item |
mediaId | Number | The AniList mediaId of the anime in the backlog |
Reference
CRUD | HTTP Verb | Example |
---|---|---|
Create | POST | Creating a new post |
Read | GET | Fetching posts for a user's feed |
Update | PUT | Changing a user's profile image |
Delete | DELETE | Deleting a comment |
Home Screen
- Parse: (Read/GET) Query all entries made by the current user
- Parse: (Delete) Delete existing entry
- AniList: (Read/GET) Query info about an anime the user has watched
Create Entry Screen
- Parse: (Create/POST) Create a new entry object
- AniList: (Read/GET) Search anime via text
Report Screen
- Parse: (Read/GET) Query all entries made by the current user
- AniList: (Read/GET) Query info about an anime the user has watched
Match Screen
- AniList: (Read/GET) Query a bunch of animes
Backlog Screen
- Parse: (Read/GET) Query all the backlog items of the current user
- Parse: (Delete) Delete existing backlog item
- AniList: (Read/GET) Query info about an anime in the backlog
// (Read/GET) Query all entries made by the current user
ParseQuery<Entry> query = ParseQuery.getQuery(Entry.class); // specify type of data
query.setLimit(20); // limit query to 20 items (implement pagination for more items)
query.whereEqualTo(Post.KEY_USER, user); // limit entries to current user's
query.addDescendingOrder("createdAt"); // order entries by creation date
query.findInBackground((entries, e) -> { // start async query for entries
// Check for errors
if (e != null) {
Log.e(TAG, "Issue with getting entries", e);
return;
}
// Do something with the list of entries
});
// (Delete) Delete existing entry
entry.deleteInBackground(e -> {
// Check for errors
if (e != null) {
Log.e(TAG, "Issue with deleting entry", e);
return;
}
// Do something after the entry is deleted
});
// (Create/POST) Create a new entry object
Entry entry = new Entry(user, mediaId, monthWatched, yearWatched, rating, note);
entry.saveInBackground(e -> {
// Check for errors
if (e != null) {
Log.e(TAG, "Error while saving entry", e);
return;
}
// Do something after the entry is created
});
// (Read/GET) Query all the backlog items of the current user
ParseQuery<BacklogItem> query = ParseQuery.getQuery(BacklogItem.class); // specify type of data
query.setLimit(20); // limit query to 20 items (implement pagination for more items)
query.whereEqualTo(Post.KEY_USER, user); // limit entries to current user's
query.addDescendingOrder("createdAt"); // order entries by creation date
query.findInBackground((items, e) -> { // start async query for entries
// Check for errors
if (e != null) {
Log.e(TAG, "Issue with getting backlog items", e);
return;
}
// Do something with the list of backlog items
});
// (Delete) Delete existing backlog item
item.deleteInBackground(e -> {
// Check for errors
if (e != null) {
Log.e(TAG, "Issue with deleting backlog item", e);
return;
}
// Do something after the backlog item is deleted
});
AniList API Base URL - https://graphql.anilist.co
HTTP Verb | Endpoint and Query Parameters | Description |
---|---|---|
GET | Media (type: ANIME, id_in: {idList}) | search animes by id list |
GET | Media (type: ANIME, search: {searchQuery}, sort: SEARCH_MATCH) | search animes by title |
GET | Media (type: ANIME, id: {mediaId}) | search anime by id |