Skip to content
Permalink
Browse files

Start displaying network logos

  • Loading branch information...
chrisbanes committed Nov 27, 2019
1 parent 8d1b8d9 commit 1df1d669926417f2bca06669cce77e599170eeac
@@ -35,7 +35,7 @@ object Libs {

const val timber = "com.jakewharton.timber:timber:4.7.1"

const val tmdbJava = "com.uwetrottmann.tmdb2:tmdb-java:2.1.1"
const val tmdbJava = "com.github.chrisbanes:tmdb-java:master-SNAPSHOT"
const val traktJava = "com.uwetrottmann.trakt5:trakt-java:6.4.0"

const val appauth = "net.openid:appauth:0.7.1"
@@ -51,6 +51,11 @@ fun textOrGoneIfEmpty(view: TextView, s: CharSequence?) {
view.isGone = s.isNullOrEmpty()
}

@BindingAdapter("goneIfNull")
fun goneIfNull(view: View, value: Any?) {
view.isGone = value == null
}

@BindingAdapter("srcRes")
fun imageViewSrcRes(view: ImageView, drawableRes: Int) {
if (drawableRes != 0) {
@@ -47,6 +47,29 @@ fun ImageView.loadBackdrop(
}
}

@BindingAdapter(
"tmdbLogoPath",
"imageSaturateOnLoad",
requireAll = false
)
fun ImageView.loadLogo(
oldPath: String?,
oldSaturateOnLoad: Boolean?,
path: String?,
saturateOnLoad: Boolean?
) {
if (oldPath != path || oldSaturateOnLoad != saturateOnLoad) {
loadImage(
null,
oldSaturateOnLoad,
0f,
path?.let { ShowTmdbImage(path = path, type = ImageType.LOGO, showId = 0) },
saturateOnLoad,
0f
)
}
}

@BindingAdapter(
"image",
"imageSaturateOnLoad",
@@ -36,11 +36,11 @@ class TmdbImageEntityCoilMapper @Inject constructor(
override fun map(data: TmdbImageEntity, size: Size): HttpUrl {
val width = if (size is PixelSize) size.width else 0

val urlProvider = tmdbImageUrlProvider.get()
return when (data.type) {
ImageType.BACKDROP -> tmdbImageUrlProvider.get()
.getBackdropUrl(data.path, width).toHttpUrl()
ImageType.POSTER -> tmdbImageUrlProvider.get()
.getPosterUrl(data.path, width).toHttpUrl()
ImageType.BACKDROP -> urlProvider.getBackdropUrl(data.path, width).toHttpUrl()
ImageType.POSTER -> urlProvider.getPosterUrl(data.path, width).toHttpUrl()
ImageType.LOGO -> urlProvider.getLogoUrl(data.path, width).toHttpUrl()
}
}
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?attr/colorOnBackground" android:alpha="0.87" />
</selector>
@@ -2,11 +2,11 @@
"formatVersion": 1,
"database": {
"version": 26,
"identityHash": "c0240bf6aae544e47f58990d02830f60",
"identityHash": "4996114c78a5cbb0e5c5c52b1d53918b",
"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, `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)",
"fields": [
{
"fieldPath": "id",
@@ -92,6 +92,12 @@
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "networkLogoPath",
"columnName": "network_logo_path",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "runtime",
"columnName": "runtime",
@@ -1085,7 +1091,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, 'c0240bf6aae544e47f58990d02830f60')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '4996114c78a5cbb0e5c5c52b1d53918b')"
]
}
}
@@ -38,7 +38,8 @@ interface TmdbImageEntity : TiviEntity {

enum class ImageType(val storageKey: String) {
BACKDROP("backdrop"),
POSTER("poster")
POSTER("poster"),
LOGO("logo"),
}

fun <T : TmdbImageEntity> Collection<T>.findHighestRatedPoster(): T? {
@@ -44,6 +44,7 @@ data class TiviShow(
@ColumnInfo(name = "first_aired") val firstAired: OffsetDateTime? = null,
@ColumnInfo(name = "country") val country: String? = null,
@ColumnInfo(name = "network") val network: String? = null,
@ColumnInfo(name = "network_logo_path") val networkLogoPath: String? = null,
@ColumnInfo(name = "runtime") val runtime: Int? = null,
@ColumnInfo(name = "genres") val _genres: String? = null,
@ColumnInfo(name = "last_trakt_data_update") val traktDataUpdate: OffsetDateTime? = null,
@@ -33,9 +33,10 @@ class TmdbImagesToShowImages @Inject constructor() : Mapper<TvShow, List<ShowTmd
type = type,
language = image.iso_639_1,
rating = image.vote_average?.toFloat() ?: 0f,
isPrimary = image.file_path!! == when (type) {
ImageType.BACKDROP -> from.backdrop_path
ImageType.POSTER -> from.poster_path
isPrimary = when (type) {
ImageType.BACKDROP -> image.file_path == from.backdrop_path
ImageType.POSTER -> image.file_path == from.poster_path
else -> false
}
)
}
@@ -28,6 +28,8 @@ class TmdbShowToTiviShow @Inject constructor() : Mapper<TvShow, TiviShow> {
imdbId = from.external_ids?.imdb_id,
title = from.name,
summary = from.overview,
homepage = from.homepage
homepage = from.homepage,
network = from.networks?.firstOrNull()?.name,
networkLogoPath = from.networks?.firstOrNull()?.logo_path
)
}
@@ -18,12 +18,15 @@ package app.tivi.data.repositories.shows

import app.tivi.data.entities.Success
import app.tivi.data.entities.TiviShow
import app.tivi.data.entities.TiviShow.Companion.EMPTY_SHOW
import app.tivi.data.instantInPast
import app.tivi.data.resultentities.ShowDetailed
import app.tivi.extensions.asyncOrAwait
import app.tivi.inject.Tmdb
import app.tivi.inject.Trakt
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.async
import org.threeten.bp.Instant

@Singleton
@@ -32,7 +35,8 @@ class ShowRepository @Inject constructor(
private val showLastRequestStore: ShowLastRequestStore,
private val showImagesLastRequestStore: ShowImagesLastRequestStore,
private val tmdbShowImagesDataSource: TmdbShowImagesDataSource,
@Trakt private val traktShowDataSource: ShowDataSource
@Trakt private val traktShowDataSource: ShowDataSource,
@Tmdb private val tmdbShowDataSource: ShowDataSource
) {
fun observeShow(showId: Long) = showStore.observeShowDetailed(showId)

@@ -45,10 +49,25 @@ class ShowRepository @Inject constructor(
*/
suspend fun updateShow(showId: Long) {
asyncOrAwait("update_show_$showId") {
val traktResult = traktShowDataSource.getShow(showStore.getShowOrEmpty(showId))
if (traktResult is Success) {
showStore.updateShowFromSources(showId, traktResult.get())
val localShow = showStore.getShowOrEmpty(showId)

val traktDeferred = async {
traktShowDataSource.getShow(localShow)
}
val tmdbDeferred = async {
tmdbShowDataSource.getShow(localShow)
}

val traktResult = traktDeferred.await()
val tmdbResult = tmdbDeferred.await()

showStore.updateShowFromSources(
showId,
traktResult.get() ?: EMPTY_SHOW,
tmdbResult.get() ?: EMPTY_SHOW
)

if (traktResult is Success) {
// If the network requests were successful, update the last request timestamp
showLastRequestStore.updateLastRequest(showId)
}
@@ -42,9 +42,9 @@ class ShowStore @Inject constructor(

suspend fun saveShow(show: TiviShow) = entityInserter.insertOrUpdate(showDao, show)

suspend fun updateShowFromSources(showId: Long, trakt: TiviShow) = transactionRunner {
suspend fun updateShowFromSources(showId: Long, trakt: TiviShow, tmdb: TiviShow) = transactionRunner {
val localShow = getShowOrEmpty(showId)
val merged = mergeShows(localShow, trakt)
val merged = mergeShows(localShow, trakt, tmdb)

if (localShow != merged) {
saveShow(merged)
@@ -109,7 +109,6 @@ class ShowStore @Inject constructor(
title = trakt.title ?: local.title,
summary = trakt.summary ?: local.summary,
homepage = trakt.homepage ?: local.homepage,
network = trakt.network ?: local.network,
certification = trakt.certification ?: local.certification,
runtime = trakt.runtime ?: local.runtime,
country = trakt.country ?: local.country,
@@ -124,6 +123,8 @@ class ShowStore @Inject constructor(
traktDataUpdate = trakt.traktDataUpdate ?: local.traktDataUpdate,

// TMDb specific stuff
tmdbId = tmdb.tmdbId ?: trakt.tmdbId ?: local.tmdbId
tmdbId = tmdb.tmdbId ?: trakt.tmdbId ?: local.tmdbId,
network = tmdb.network ?: trakt.network ?: local.network,
networkLogoPath = tmdb.networkLogoPath ?: local.networkLogoPath
)
}
@@ -36,4 +36,14 @@ object TmdbImageSizes {
"w1280",
"original"
)

val logoSizes = listOf(
"w45",
"w92",
"w154",
"w185",
"w300",
"w500",
"original"
)
}
@@ -21,7 +21,8 @@ private val IMAGE_SIZE_PATTERN = "w(\\d+)$".toRegex()
data class TmdbImageUrlProvider(
private val baseImageUrl: String = TmdbImageSizes.baseImageUrl,
private val posterSizes: List<String> = TmdbImageSizes.posterSizes,
private val backdropSizes: List<String> = TmdbImageSizes.backdropSizes
private val backdropSizes: List<String> = TmdbImageSizes.backdropSizes,
private val logoSizes: List<String> = TmdbImageSizes.logoSizes
) {
fun getPosterUrl(path: String, imageWidth: Int): String {
return "$baseImageUrl${selectSize(posterSizes, imageWidth)}$path"
@@ -31,6 +32,10 @@ data class TmdbImageUrlProvider(
return "$baseImageUrl${selectSize(backdropSizes, imageWidth)}$path"
}

fun getLogoUrl(path: String, imageWidth: Int): String {
return "$baseImageUrl${selectSize(logoSizes, imageWidth)}$path"
}

private fun selectSize(sizes: List<String>, imageWidth: Int): String {
var previousSize: String? = null
var previousWidth = 0
@@ -60,7 +60,9 @@ class TmdbManager @Inject constructor(
val newProvider = TmdbImageUrlProvider(
images.secure_base_url!!,
images.poster_sizes ?: emptyList(),
images.backdrop_sizes ?: emptyList())
images.backdrop_sizes ?: emptyList(),
images.logo_sizes ?: emptyList()
)
imageProviderSubject.send(newProvider)
}
}
@@ -25,7 +25,7 @@
</data>

<LinearLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:transitionGroup="true"
@@ -39,6 +39,16 @@
android:layout_marginBottom="@dimen/spacing_micro"
android:textAppearance="?attr/textAppearanceSubtitle2" />

<ImageView
android:layout_width="wrap_content"
android:layout_height="28dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:tint="@color/color_on_background_87"
app:goneIfNull="@{tiviShow.networkLogoPath}"
app:imageSaturateOnLoad="@{false}"
app:tmdbLogoPath="@{tiviShow.networkLogoPath}" />

<app.tivi.ui.widget.BaselineGridTextView
android:id="@+id/details_info_content"
android:layout_width="wrap_content"
@@ -47,6 +57,7 @@
android:gravity="center"
android:text="@{tiviShow.network}"
android:textAppearance="?attr/textAppearanceBody2"
app:visible="@{tiviShow.networkLogoPath == null}"
tools:text="HBO" />

</LinearLayout>

0 comments on commit 1df1d66

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