From e4a4c5acce4c69df924702de1a1b408903e34f07 Mon Sep 17 00:00:00 2001 From: Owen LeJeune Date: Sun, 16 Jul 2023 17:49:07 -0400 Subject: [PATCH] add additional details to person known for --- .../owenlejeune/tvtime/api/DateTypeAdapter.kt | 2 +- .../api/tmdb/api/v3/model/DetailPerson.kt | 5 +- .../tvtime/extensions/DateExtensions.kt | 18 ++++++- .../tvtime/ui/components/DetailViewCommon.kt | 30 +++++++++++ .../tvtime/ui/screens/MediaDetailScreen.kt | 29 +---------- .../tvtime/ui/screens/PeopleDetailScreen.kt | 51 +++++++++++++++++++ app/src/main/res/values/strings.xml | 4 ++ 7 files changed, 107 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/DateTypeAdapter.kt b/app/src/main/java/com/owenlejeune/tvtime/api/DateTypeAdapter.kt index b18da74..724206e 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/DateTypeAdapter.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/DateTypeAdapter.kt @@ -20,7 +20,7 @@ class DateTypeAdapter: TypeAdapter() { override fun read(jrIn: JsonReader): Date? { if (jrIn.peek() == JsonToken.NULL) { jrIn.nextNull() - throw Exception("JSON must not be null") + return null } val dateFields = jrIn.nextString() if (dateFields.isEmpty()) { diff --git a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailPerson.kt b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailPerson.kt index bd03f84..b7f1d71 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailPerson.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/api/tmdb/api/v3/model/DetailPerson.kt @@ -2,11 +2,12 @@ package com.owenlejeune.tvtime.api.tmdb.api.v3.model import com.google.gson.annotations.SerializedName import com.owenlejeune.tvtime.utils.types.Gender +import java.util.Date class DetailPerson( - @SerializedName("birthday") val birthday: String, + @SerializedName("birthday") val birthday: Date, @SerializedName("known_for_department") val knownFor: String, - @SerializedName("deathday") val dateOfDeath: String?, + @SerializedName("deathday") val dateOfDeath: Date?, @SerializedName("biography") val biography: String, @SerializedName("place_of_birth") val birthplace: String?, @SerializedName("adult") val isAdult: Boolean, diff --git a/app/src/main/java/com/owenlejeune/tvtime/extensions/DateExtensions.kt b/app/src/main/java/com/owenlejeune/tvtime/extensions/DateExtensions.kt index cb18d35..f594921 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/extensions/DateExtensions.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/extensions/DateExtensions.kt @@ -1,6 +1,10 @@ package com.owenlejeune.tvtime.extensions import java.text.SimpleDateFormat +import java.time.Instant +import java.time.LocalDate +import java.time.Period +import java.time.ZoneId import java.util.Calendar import java.util.Date import java.util.Locale @@ -16,6 +20,18 @@ fun Date.format(format: DateFormat): String { return formatter.format(this) } +fun Date.toLocalDate() = Instant.ofEpochMilli(time) + .atZone(ZoneId.systemDefault()) + .toLocalDate() + +fun Date.yearsSince(anchorDate: Date? = null): Int { + val endDate = anchorDate?.toLocalDate() ?: LocalDate.now() + val thisLocalDate = toLocalDate() + + return Period.between(thisLocalDate, endDate).years +} + enum class DateFormat(val format: String) { - MMMM_dd("MMMM dd") + MMMM_dd("MMMM dd"), + MMMM_dd_yyyy("MMMM dd yyyy") } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/components/DetailViewCommon.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/components/DetailViewCommon.kt index 1cf588a..8fcc501 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/components/DetailViewCommon.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/components/DetailViewCommon.kt @@ -8,9 +8,11 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Divider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -26,6 +28,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel import coil.compose.AsyncImage import coil.compose.rememberAsyncImagePainter @@ -331,4 +334,31 @@ fun PlaceholderDetailHeader() { ) } } +} + +@Composable +fun AdditionalDetailItem( + title: String, + subtext: String, + includeDivider: Boolean = true +) { + Column( + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + Text( + text = title, + fontSize = 16.sp, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.padding(horizontal = 16.dp) + ) + Text( + text = subtext, + fontSize = 14.sp, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = 16.dp) + ) + if (includeDivider) { + Divider() + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt index adf0c36..16f557b 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/MediaDetailScreen.kt @@ -99,6 +99,7 @@ import com.owenlejeune.tvtime.extensions.listItems import com.owenlejeune.tvtime.extensions.shimmerBackground import com.owenlejeune.tvtime.preferences.AppPreferences import com.owenlejeune.tvtime.ui.components.ActionsView +import com.owenlejeune.tvtime.ui.components.AdditionalDetailItem import com.owenlejeune.tvtime.ui.components.AvatarImage import com.owenlejeune.tvtime.ui.components.BackButton import com.owenlejeune.tvtime.ui.components.ChipDefaults @@ -796,34 +797,6 @@ private fun AdditionalTvItems( ) } -@Composable -private fun AdditionalDetailItem( - title: String, - subtext: String, - includeDivider: Boolean = true -) { - Column( - verticalArrangement = Arrangement.spacedBy(8.dp) - ) { - Text( - text = title, - fontSize = 16.sp, - color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.padding(horizontal = 16.dp) - ) - Text( - text = subtext, - fontSize = 14.sp, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(horizontal = 16.dp) - ) - if (includeDivider) { - Divider() - } - } -} - - @Composable private fun CastCard( itemId: Int, diff --git a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/PeopleDetailScreen.kt b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/PeopleDetailScreen.kt index 2d918e1..3055581 100644 --- a/app/src/main/java/com/owenlejeune/tvtime/ui/screens/PeopleDetailScreen.kt +++ b/app/src/main/java/com/owenlejeune/tvtime/ui/screens/PeopleDetailScreen.kt @@ -46,7 +46,13 @@ import androidx.navigation.NavController import com.google.accompanist.pager.ExperimentalPagerApi import com.owenlejeune.tvtime.R import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailPerson +import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedMovie +import com.owenlejeune.tvtime.api.tmdb.api.v3.model.DetailedTv +import com.owenlejeune.tvtime.extensions.DateFormat import com.owenlejeune.tvtime.extensions.combinedOnVisibilityChange +import com.owenlejeune.tvtime.extensions.format +import com.owenlejeune.tvtime.extensions.yearsSince +import com.owenlejeune.tvtime.ui.components.AdditionalDetailItem import com.owenlejeune.tvtime.ui.components.BackButton import com.owenlejeune.tvtime.ui.components.ContentCard import com.owenlejeune.tvtime.ui.components.DetailHeader @@ -173,6 +179,8 @@ fun PersonDetailScreen( CreditsCard(personId = personId, appNavController = appNavController) + AdditionalDetailsCard(id = personId, mainViewModel = mainViewModel) + ImagesCard(id = personId, appNavController = appNavController) } @@ -206,6 +214,49 @@ private fun BiographyCard(person: DetailPerson?) { } } +@Composable +private fun AdditionalDetailsCard( + id: Int, + mainViewModel: MainViewModel, + modifier: Modifier = Modifier +) { + val personMap = remember { mainViewModel.peopleMap } + val person = personMap[id] + + ContentCard( + modifier = modifier, + title = stringResource(R.string.additional_details_title) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight() + .padding(vertical = 12.dp), + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + AdditionalDetailItem( + title = stringResource(R.string.also_known_as), + subtext = person?.alsoKnownAs?.joinToString(separator = ", ") ?: "" + ) + AdditionalDetailItem( + title = stringResource(R.string.place_of_birth), + subtext = person?.birthplace ?: "" + ) + val birthday = person?.birthday + AdditionalDetailItem( + title = stringResource(R.string.birthday), + subtext = "${birthday?.format(DateFormat.MMMM_dd_yyyy) ?: ""} (${birthday?.yearsSince(person.dateOfDeath)} years old)" + ) + person?.dateOfDeath?.let { + AdditionalDetailItem( + title = stringResource(R.string.date_of_death), + subtext = it.format(DateFormat.MMMM_dd_yyyy) + ) + } + } + } +} + @Composable private fun CreditsCard( personId: Int, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb29be1..b4ecdfd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -256,4 +256,8 @@ See all cast and crew Unreleased TBA + Also Known As + Place of birth + Birthday + Date of death \ No newline at end of file