Skip to content
11 changes: 11 additions & 0 deletions .agent/skills/material-thinking/references/m3-expressive.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ M3 Expressiveは、標準のMaterial 3を拡張し、以下を実現します:

URL: https://m3.material.io/blog/building-with-m3-expressive

### Research & Philosophy (Google Design 2024-2025)

Base on "Expressive Design: Google's UX Research":
- **Emotional Connection**: 87% of users aged 18-24 prefer expressive designs.
- **Usability**: Expressive elements (larger, bolder, colorful) help users spot key UI elements up to 4x faster.
- **Brand Relevance**: Expressive design increases perception of "modernity" (+34%) and "subculture relevance" (+32%).
- **Context is Key**: Don't sacrifice standard patterns (e.g., lists) for expression if it hurts usability.
- **Accessibility**: Expressive design (larger targets, high contrast) often improves accessibility for older adults and those with varying abilities.

Key Takeaway: Use bold colors and shapes not just for decoration, but to *guide attention* and *improve task speed*.

---

## Usability Principles
Expand Down
4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ android {
applicationId = "com.ivor.openanime"
minSdk = 26
targetSdk = 36
versionCode = 2
versionName = "1.1"
versionCode = 3
versionName = "1.2"

val localProperties = Properties()
val localPropertiesFile = rootProject.file("local.properties")
Expand Down
19 changes: 19 additions & 0 deletions app/src/main/java/com/ivor/openanime/data/remote/TmdbApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,25 @@ interface TmdbApi {
@Query("with_keywords") keywords: String = "210024|287501" // Optionally specify anime-specific keywords
): TmdbResponse<AnimeDto>

@GET("trending/tv/{time_window}")
suspend fun getTrendingAnime(
@Path("time_window") timeWindow: String = "day",
@Query("page") page: Int = 1
): TmdbResponse<AnimeDto>

@GET("tv/top_rated")
suspend fun getTopRatedAnime(
@Query("page") page: Int = 1,
@Query("language") language: String = "en-US"
): TmdbResponse<AnimeDto>

@GET("tv/airing_today")
suspend fun getAiringTodayAnime(
@Query("page") page: Int = 1,
@Query("language") language: String = "en-US",
@Query("timezone") timezone: String = "America/New_York"
): TmdbResponse<AnimeDto>

@GET("search/multi")
suspend fun searchMulti(
@Query("query") query: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ data class AnimeDetailsDto(
@SerialName("number_of_seasons") val numberOfSeasons: Int? = null,
@SerialName("number_of_episodes") val numberOfEpisodes: Int? = null,
@SerialName("seasons") val seasons: List<SeasonDto>? = null,
@SerialName("runtime") val runtime: Int? = null
@SerialName("runtime") val runtime: Int? = null,
@SerialName("status") val status: String? = null,
@SerialName("tagline") val tagline: String? = null,
@SerialName("genres") val genres: List<GenreDto>? = null,
@SerialName("production_companies") val productionCompanies: List<ProductionCompanyDto>? = null,
@SerialName("homepage") val homepage: String? = null
) {
val name: String
get() = movieTitle ?: tvName ?: ""
Expand All @@ -51,6 +56,20 @@ data class AnimeDetailsDto(
get() = releaseDate ?: firstAirDate ?: ""
}

@Serializable
data class GenreDto(
@SerialName("id") val id: Int,
@SerialName("name") val name: String
)

@Serializable
data class ProductionCompanyDto(
@SerialName("id") val id: Int,
@SerialName("name") val name: String,
@SerialName("logo_path") val logoPath: String? = null,
@SerialName("origin_country") val originCountry: String? = null
)

fun AnimeDetailsDto.toAnimeDto(mediaType: String): AnimeDto {
return AnimeDto(
id = id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ class AnimeRepositoryImpl @Inject constructor(
api.getPopularAnime(page = page).results
}

override suspend fun getTrendingAnime(timeWindow: String, page: Int): Result<List<AnimeDto>> = runCatching {
api.getTrendingAnime(timeWindow, page).results
}

override suspend fun getTopRatedAnime(page: Int): Result<List<AnimeDto>> = runCatching {
api.getTopRatedAnime(page).results
}

override suspend fun getAiringTodayAnime(page: Int): Result<List<AnimeDto>> = runCatching {
api.getAiringTodayAnime(page).results
}

override suspend fun searchAnime(query: String, page: Int, filter: String): Result<List<AnimeDto>> = runCatching {
when (filter) {
"movie" -> api.searchMovie(query, page).results.map { it.copy(mediaType = "movie") }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import com.ivor.openanime.data.remote.model.SeasonDetailsDto

interface AnimeRepository {
suspend fun getPopularAnime(page: Int): Result<List<AnimeDto>>
suspend fun getTrendingAnime(timeWindow: String = "day", page: Int = 1): Result<List<AnimeDto>>
suspend fun getTopRatedAnime(page: Int = 1): Result<List<AnimeDto>>
suspend fun getAiringTodayAnime(page: Int = 1): Result<List<AnimeDto>>

suspend fun searchAnime(query: String, page: Int, filter: String = "all"): Result<List<AnimeDto>>
suspend fun getAnimeDetails(id: Int): Result<AnimeDetailsDto>
suspend fun getMovieDetails(id: Int): Result<AnimeDetailsDto>
Expand Down
Loading