Skip to content
Permalink
Browse files

Start showing airs time/day in show details

  • Loading branch information
chrisbanes committed Nov 27, 2019
1 parent d87321d commit e1c2e15573114e8bb3219150c86e7f8c0401528f
@@ -26,6 +26,7 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.preference.PreferenceManager
import app.tivi.BuildConfig
import app.tivi.TiviApplication
import app.tivi.extensions.toThreeTenDateTimeFormatter
import app.tivi.home.followed.R
import app.tivi.util.AppCoroutineDispatchers
import dagger.Module
@@ -102,10 +103,9 @@ class AppModule {
@Provides
@MediumDate
fun provideMediumDateFormatter(application: TiviApplication): DateTimeFormatter {
val dateF = AndroidDateFormat.getMediumDateFormat(application) as SimpleDateFormat

@Suppress("DEPRECATION")
return DateTimeFormatter.ofPattern(dateF.toPattern())
return (AndroidDateFormat.getMediumDateFormat(application) as SimpleDateFormat)
.toThreeTenDateTimeFormatter()
.withLocale(application.resources.configuration.locale)
.withZone(ZoneId.systemDefault())
}
@@ -127,14 +127,22 @@ class AppModule {
@Provides
@ShortDate
fun provideShortDateFormatter(application: TiviApplication): DateTimeFormatter {
val dateF = AndroidDateFormat.getDateFormat(application) as SimpleDateFormat

@Suppress("DEPRECATION")
return DateTimeFormatter.ofPattern(dateF.toPattern())
return (AndroidDateFormat.getDateFormat(application) as SimpleDateFormat)
.toThreeTenDateTimeFormatter()
.withLocale(application.resources.configuration.locale)
.withZone(ZoneId.systemDefault())
}

@Singleton
@Provides
@ShortTime
fun provideShortTimeFormatter(application: TiviApplication): DateTimeFormatter {
@Suppress("DEPRECATION")
return (AndroidDateFormat.getTimeFormat(application) as SimpleDateFormat)
.toThreeTenDateTimeFormatter()
}

@Provides
@ProcessLifetime
fun provideLongLifetimeScope(): CoroutineScope {
@@ -0,0 +1,24 @@
/*
* Copyright 2019 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package app.tivi.extensions

import java.text.SimpleDateFormat
import org.threeten.bp.format.DateTimeFormatter

fun SimpleDateFormat.toThreeTenDateTimeFormatter(): DateTimeFormatter {
return DateTimeFormatter.ofPattern(toPattern())
}
@@ -20,12 +20,17 @@ import android.text.format.DateUtils
import app.tivi.inject.MediumDate
import app.tivi.inject.MediumDateTime
import app.tivi.inject.ShortDate
import app.tivi.inject.ShortTime
import javax.inject.Inject
import javax.inject.Singleton
import org.threeten.bp.LocalTime
import org.threeten.bp.OffsetDateTime
import org.threeten.bp.format.DateTimeFormatter
import org.threeten.bp.temporal.Temporal

@Singleton
class TiviDateFormatter @Inject constructor(
@ShortTime private val shortTimeFormatter: DateTimeFormatter,
@ShortDate private val shortDateFormatter: DateTimeFormatter,
@MediumDate private val mediumDateFormatter: DateTimeFormatter,
@MediumDateTime private val mediumDateTimeFormatter: DateTimeFormatter
@@ -36,6 +41,8 @@ class TiviDateFormatter @Inject constructor(

fun formatMediumDateTime(temporalAmount: Temporal): String = mediumDateTimeFormatter.format(temporalAmount)

fun formatShortTime(localTime: LocalTime): String = shortTimeFormatter.format(localTime)

fun formatShortRelativeTime(dateTime: OffsetDateTime?): CharSequence? {
if (dateTime == null) {
return null
@@ -43,6 +43,11 @@ annotation class MediumDateTime
@MustBeDocumented
annotation class ShortDate

@Retention(AnnotationRetention.RUNTIME)
@Qualifier
@MustBeDocumented
annotation class ShortTime

@Retention(AnnotationRetention.RUNTIME)
@Qualifier
@MustBeDocumented
@@ -151,4 +151,7 @@
<string name="status_active">Continuing</string>
<string name="status_in_production">In production</string>

<string name="airs_title">Airs</string>
<string name="airs_text">%1$s at %2$s</string>

</resources>
@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 26,
"identityHash": "4996114c78a5cbb0e5c5c52b1d53918b",
"identityHash": "9597ae3e4d6c8012a30ac4303399f9e5",
"entities": [
{
"tableName": "shows",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `original_title` TEXT, `trakt_id` INTEGER, `tmdb_id` INTEGER, `imdb_id` TEXT, `overview` TEXT, `homepage` TEXT, `trakt_rating` REAL, `trakt_votes` INTEGER, `certification` TEXT, `first_aired` TEXT, `country` TEXT, `network` TEXT, `network_logo_path` TEXT, `runtime` INTEGER, `genres` TEXT, `last_trakt_data_update` TEXT, `status` TEXT)",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `original_title` TEXT, `trakt_id` INTEGER, `tmdb_id` INTEGER, `imdb_id` TEXT, `overview` TEXT, `homepage` TEXT, `trakt_rating` REAL, `trakt_votes` INTEGER, `certification` TEXT, `first_aired` TEXT, `country` TEXT, `network` TEXT, `network_logo_path` TEXT, `runtime` INTEGER, `genres` TEXT, `last_trakt_data_update` TEXT, `status` TEXT, `airs_day` INTEGER, `airs_time` TEXT, `airs_tz` TEXT)",
"fields": [
{
"fieldPath": "id",
@@ -121,6 +121,24 @@
"columnName": "status",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "airsDay",
"columnName": "airs_day",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "airsTime",
"columnName": "airs_time",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "airsTimeZone",
"columnName": "airs_tz",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
@@ -1091,7 +1109,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4996114c78a5cbb0e5c5c52b1d53918b')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9597ae3e4d6c8012a30ac4303399f9e5')"
]
}
}
@@ -21,8 +21,11 @@ import app.tivi.data.entities.ImageType
import app.tivi.data.entities.PendingAction
import app.tivi.data.entities.Request
import app.tivi.data.entities.ShowStatus
import org.threeten.bp.DayOfWeek
import org.threeten.bp.Instant
import org.threeten.bp.LocalTime
import org.threeten.bp.OffsetDateTime
import org.threeten.bp.ZoneId
import org.threeten.bp.format.DateTimeFormatter

object TiviTypeConverters {
@@ -32,6 +35,7 @@ object TiviTypeConverters {
private val imageTypeValues by lazy(LazyThreadSafetyMode.NONE) { ImageType.values() }
private val pendingActionValues by lazy(LazyThreadSafetyMode.NONE) { PendingAction.values() }
private val showStatusValues by lazy(LazyThreadSafetyMode.NONE) { ShowStatus.values() }
private val dayOfWeekValues by lazy(LazyThreadSafetyMode.NONE) { DayOfWeek.values() }

@TypeConverter
@JvmStatic
@@ -41,6 +45,32 @@ object TiviTypeConverters {
@JvmStatic
fun fromOffsetDateTime(date: OffsetDateTime?): String? = date?.format(formatter)

@TypeConverter
@JvmStatic
fun toZoneId(value: String?) = value?.let { ZoneId.of(it) }

@TypeConverter
@JvmStatic
fun fromZoneId(value: ZoneId?) = value?.id

@TypeConverter
@JvmStatic
fun toLocalTime(value: String?) = value?.let { LocalTime.parse(value) }

@TypeConverter
@JvmStatic
fun fromLocalTime(value: LocalTime?) = value?.format(DateTimeFormatter.ISO_LOCAL_TIME)

@TypeConverter
@JvmStatic
fun toDayOfWeek(value: Int?): DayOfWeek? {
return if (value != null) { dayOfWeekValues.firstOrNull { it.value == value } } else null
}

@TypeConverter
@JvmStatic
fun fromDayOfWeek(day: DayOfWeek?) = day?.value

@TypeConverter
@JvmStatic
fun toInstant(value: Long?) = value?.let { Instant.ofEpochMilli(it) }
@@ -21,7 +21,10 @@ import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import org.threeten.bp.DayOfWeek
import org.threeten.bp.LocalTime
import org.threeten.bp.OffsetDateTime
import org.threeten.bp.ZoneId

@Entity(tableName = "shows",
indices = [
@@ -48,7 +51,10 @@ data class TiviShow(
@ColumnInfo(name = "runtime") val runtime: Int? = null,
@ColumnInfo(name = "genres") val _genres: String? = null,
@ColumnInfo(name = "last_trakt_data_update") val traktDataUpdate: OffsetDateTime? = null,
@ColumnInfo(name = "status") val status: ShowStatus? = null
@ColumnInfo(name = "status") val status: ShowStatus? = null,
@ColumnInfo(name = "airs_day") val airsDay: DayOfWeek? = null,
@ColumnInfo(name = "airs_time") val airsTime: LocalTime? = null,
@ColumnInfo(name = "airs_tz") val airsTimeZone: ZoneId? = null
) : TiviEntity, TraktIdEntity, TmdbIdEntity {
@Ignore constructor() : this(0)

@@ -18,8 +18,13 @@ package app.tivi.data.mappers

import app.tivi.data.entities.TiviShow
import com.uwetrottmann.trakt5.entities.Show
import java.util.Locale
import javax.inject.Inject
import javax.inject.Singleton
import org.threeten.bp.DayOfWeek
import org.threeten.bp.LocalTime
import org.threeten.bp.ZoneId
import org.threeten.bp.format.TextStyle

@Singleton
class TraktShowToTiviShow @Inject constructor(
@@ -41,6 +46,27 @@ class TraktShowToTiviShow @Inject constructor(
firstAired = from.first_aired,
_genres = from.genres?.joinToString(","),
traktDataUpdate = from.updated_at,
status = from.status?.let { statusMapper.map(it) }
status = from.status?.let {
statusMapper.map(it)
},
airsDay = from.airs?.day?.let { dayString ->
DayOfWeek.values().firstOrNull { day ->
dayString.equals(day.getDisplayName(TextStyle.FULL, Locale.getDefault()), true)
}
},
airsTime = from.airs?.time?.let {
try {
LocalTime.parse(it)
} catch (e: Exception) {
null
}
},
airsTimeZone = from.airs?.timezone?.let {
try {
ZoneId.of(it)
} catch (e: Exception) {
null
}
}
)
}
@@ -115,6 +115,9 @@ class ShowStore @Inject constructor(
firstAired = trakt.firstAired ?: local.firstAired,
_genres = trakt._genres ?: local._genres,
status = trakt.status ?: local.status,
airsDay = trakt.airsDay ?: local.airsDay,
airsTimeZone = trakt.airsTimeZone ?: local.airsTimeZone,
airsTime = trakt.airsTime ?: local.airsTime,

// Trakt specific stuff
traktId = trakt.traktId ?: local.traktId,
@@ -131,6 +131,14 @@ class ShowDetailsEpoxyController @Inject constructor(
textCreator(textCreator)
}
}
if (show.airsTime != null && show.airsDay != null && show.airsTimeZone != null &&
(show.status == null || show.status == ShowStatus.RETURNING)) {
badges += DetailsInfoAirsBindingModel_().apply {
id("airs")
tiviShow(show)
textCreator(textCreator)
}
}
if (badges.isNotEmpty()) {
EpoxyModelGroup(R.layout.layout_show_details_info_holder, badges)
.addTo(this)
@@ -26,13 +26,18 @@ import app.tivi.data.entities.Episode
import app.tivi.data.entities.Genre
import app.tivi.data.entities.Season
import app.tivi.data.entities.ShowStatus
import app.tivi.data.entities.TiviShow
import app.tivi.data.resultentities.SeasonWithEpisodesAndWatches
import app.tivi.data.views.FollowedShowsWatchStats
import app.tivi.inject.PerActivity
import app.tivi.ui.GenreStringer
import app.tivi.util.TiviDateFormatter
import java.util.Locale
import javax.inject.Inject
import org.threeten.bp.OffsetDateTime
import org.threeten.bp.ZoneId
import org.threeten.bp.ZonedDateTime
import org.threeten.bp.format.TextStyle

class ShowDetailsTextCreator @Inject constructor(
@PerActivity private val context: Context,
@@ -123,6 +128,29 @@ class ShowDetailsTextCreator @Inject constructor(
}
}

fun airsText(show: TiviShow): CharSequence? {
val airTime = show.airsTime
val airTz = show.airsTimeZone
val airDay = show.airsDay

if (airTime == null || airTz == null || airDay == null) {
// If we don't have all the necessary info, return null
return null
}

val local = ZonedDateTime.now()
.withZoneSameLocal(airTz)
.with(show.airsDay)
.with(airTime)
.withZoneSameInstant(ZoneId.systemDefault())

return context.getString(
R.string.airs_text,
local.dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.getDefault()),
tiviDateFormatter.formatShortTime(local.toLocalTime())
)
}

fun showStatusText(status: ShowStatus): CharSequence = when (status) {
ShowStatus.CANCELED, ShowStatus.ENDED -> context.getString(R.string.status_ended)
ShowStatus.RETURNING -> context.getString(R.string.status_active)

0 comments on commit e1c2e15

Please sign in to comment.
You can’t perform that action at this time.