mirror of
https://github.com/owenlejeune/TVTime.git
synced 2025-11-19 10:11:13 -05:00
show trailers
This commit is contained in:
@@ -85,6 +85,11 @@ dependencies {
|
|||||||
|
|
||||||
implementation "me.onebone:toolbar-compose:2.3.1"
|
implementation "me.onebone:toolbar-compose:2.3.1"
|
||||||
|
|
||||||
|
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
|
||||||
|
implementation 'com.github.HaarigerHarald:android-youtubeExtractor:v2.1.0'
|
||||||
|
implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:core:11.0.1'
|
||||||
|
implementation 'com.pierfrancescosoffritti.androidyoutubeplayer:chromecast-sender:0.26'
|
||||||
|
|
||||||
testImplementation "junit:junit:${Versions.junit}"
|
testImplementation "junit:junit:${Versions.junit}"
|
||||||
androidTestImplementation "androidx.test.ext:junit:${Versions.androidx_junit}"
|
androidTestImplementation "androidx.test.ext:junit:${Versions.androidx_junit}"
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-core:${Versions.espresso_core}"
|
androidTestImplementation "androidx.test.espresso:espresso-core:${Versions.espresso_core}"
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.TVTime">
|
android:theme="@style/Theme.TVTime"
|
||||||
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.TVTime"
|
android:theme="@style/Theme.TVTime">
|
||||||
android:screenOrientation="portrait">
|
<!-- android:screenOrientation="portrait">-->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package com.owenlejeune.tvtime.api.tmdb
|
package com.owenlejeune.tvtime.api.tmdb
|
||||||
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.CastAndCrew
|
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.ImageCollection
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.DetailedItem
|
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.HomePageResponse
|
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
|
|
||||||
interface DetailService {
|
interface DetailService {
|
||||||
@@ -16,4 +13,6 @@ interface DetailService {
|
|||||||
|
|
||||||
suspend fun getSimilar(id: Int, page: Int): Response<out HomePageResponse>
|
suspend fun getSimilar(id: Int, page: Int): Response<out HomePageResponse>
|
||||||
|
|
||||||
|
suspend fun getVideos(id: Int): Response<VideoResponse>
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -35,4 +35,7 @@ interface MoviesApi {
|
|||||||
@GET("movie/{id}/recommendations")
|
@GET("movie/{id}/recommendations")
|
||||||
suspend fun getSimilarMovies(@Path("id") id: Int, @Query("page") page: Int = 1): Response<HomePageMoviesResponse>
|
suspend fun getSimilarMovies(@Path("id") id: Int, @Query("page") page: Int = 1): Response<HomePageMoviesResponse>
|
||||||
|
|
||||||
|
@GET("movie/{id}/videos")
|
||||||
|
suspend fun getVideos(@Path("id") id: Int): Response<VideoResponse>
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -44,4 +44,8 @@ class MoviesService: KoinComponent, DetailService, HomePageService {
|
|||||||
return service.getSimilarMovies(id, page)
|
return service.getSimilarMovies(id, page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getVideos(id: Int): Response<VideoResponse> {
|
||||||
|
return service.getVideos(id)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -35,4 +35,7 @@ interface TvApi {
|
|||||||
@GET("tv/{id}/similar")
|
@GET("tv/{id}/similar")
|
||||||
suspend fun getSimilarTvShows(@Path("id") id: Int, @Query("page") page: Int = 1): Response<HomePageTvResponse>
|
suspend fun getSimilarTvShows(@Path("id") id: Int, @Query("page") page: Int = 1): Response<HomePageTvResponse>
|
||||||
|
|
||||||
|
@GET("tv/{id}/videos")
|
||||||
|
suspend fun getVideos(@Path("id") id: Int): Response<VideoResponse>
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -43,4 +43,8 @@ class TvService: KoinComponent, DetailService, HomePageService {
|
|||||||
override suspend fun getSimilar(id: Int, page: Int): Response<out HomePageResponse> {
|
override suspend fun getSimilar(id: Int, page: Int): Response<out HomePageResponse> {
|
||||||
return service.getSimilarTvShows(id, page)
|
return service.getSimilarTvShows(id, page)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getVideos(id: Int): Response<VideoResponse> {
|
||||||
|
return service.getVideos(id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class Video(
|
||||||
|
@SerializedName("iso_639_1") val language: String,
|
||||||
|
@SerializedName("iso_3166_1") val region: String,
|
||||||
|
@SerializedName("name") val name: String,
|
||||||
|
@SerializedName("key") val key: String,
|
||||||
|
@SerializedName("site") val site: String,
|
||||||
|
@SerializedName("size") val size: Int,
|
||||||
|
@SerializedName("type") val type: String,
|
||||||
|
@SerializedName("official") val isOfficial: Boolean
|
||||||
|
)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.owenlejeune.tvtime.api.tmdb.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
class VideoResponse(
|
||||||
|
@SerializedName("results") val results: List<Video>
|
||||||
|
)
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
package com.owenlejeune.tvtime.ui.components
|
package com.owenlejeune.tvtime.ui.components
|
||||||
|
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
|
import android.util.SparseArray
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.gestures.detectTapGestures
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
@@ -17,8 +20,11 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
@@ -42,7 +48,23 @@ import androidx.compose.ui.unit.Dp
|
|||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import at.huber.youtubeExtractor.VideoMeta
|
||||||
|
import at.huber.youtubeExtractor.YouTubeExtractor
|
||||||
|
import at.huber.youtubeExtractor.YtFile
|
||||||
|
import coil.compose.rememberImagePainter
|
||||||
import com.google.accompanist.flowlayout.FlowRow
|
import com.google.accompanist.flowlayout.FlowRow
|
||||||
|
import com.google.android.exoplayer2.ExoPlayer
|
||||||
|
import com.google.android.exoplayer2.MediaItem
|
||||||
|
import com.google.android.exoplayer2.SimpleExoPlayer
|
||||||
|
import com.google.android.exoplayer2.ui.PlayerView
|
||||||
|
import com.owenlejeune.tvtime.R
|
||||||
|
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer
|
||||||
|
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener
|
||||||
|
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.YouTubePlayerFullScreenListener
|
||||||
|
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TopLevelSwitch(
|
fun TopLevelSwitch(
|
||||||
@@ -387,3 +409,132 @@ fun RoundedTextField(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class)
|
||||||
|
@Composable
|
||||||
|
fun FullScreenThumbnailVideoPlayer(
|
||||||
|
key: String,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
val showFullscreenView = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
Image(
|
||||||
|
modifier = modifier
|
||||||
|
.clickable(
|
||||||
|
onClick = {
|
||||||
|
showFullscreenView.value = true
|
||||||
|
}
|
||||||
|
),
|
||||||
|
painter = rememberImagePainter(
|
||||||
|
data = "https://img.youtube.com/vi/${key}/hqdefault.jpg",
|
||||||
|
builder = {
|
||||||
|
placeholder(R.drawable.placeholder)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
contentDescription = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
if (showFullscreenView.value) {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = { showFullscreenView.value = false },
|
||||||
|
properties = DialogProperties(usePlatformDefaultWidth = false)
|
||||||
|
) {
|
||||||
|
Surface(modifier = Modifier.fillMaxWidth().wrapContentHeight()) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.wrapContentHeight().fillMaxWidth(),
|
||||||
|
factory = {
|
||||||
|
YouTubePlayerView(context).apply {
|
||||||
|
addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
||||||
|
override fun onReady(youTubePlayer: YouTubePlayer) {
|
||||||
|
youTubePlayer.loadVideo(key, 0f)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// Text("big dialog")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// AndroidView(
|
||||||
|
// modifier = modifier,
|
||||||
|
// factory = {
|
||||||
|
// val player = YouTubePlayerView(context).apply {
|
||||||
|
// var ytPlayer: YouTubePlayer? = null
|
||||||
|
// addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
||||||
|
// override fun onReady(youTubePlayer: YouTubePlayer) {
|
||||||
|
// ytPlayer = youTubePlayer
|
||||||
|
// youTubePlayer.loadVideo(key, 0f)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// addFullScreenListener(object : YouTubePlayerFullScreenListener {
|
||||||
|
// override fun onYouTubePlayerEnterFullScreen() {
|
||||||
|
// ytPlayer?.play()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onYouTubePlayerExitFullScreen() {
|
||||||
|
// ytPlayer?.pause()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// player.enterFullScreen()
|
||||||
|
//
|
||||||
|
// player
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
// val lifecyclerOwner = LocalLifecycleOwner.current
|
||||||
|
// val showFullscreenView = remember { mutableStateOf(false) }
|
||||||
|
//
|
||||||
|
// if (!showFullscreenView.value) {
|
||||||
|
// Image(
|
||||||
|
// modifier = modifier
|
||||||
|
// .clickable(
|
||||||
|
// onClick = {
|
||||||
|
// showFullscreenView.value = true
|
||||||
|
// }
|
||||||
|
// ),
|
||||||
|
// painter = rememberImagePainter(
|
||||||
|
// data = "https://img.youtube.com/vi/${key}/hqdefault.jpg",
|
||||||
|
// builder = {
|
||||||
|
// placeholder(R.drawable.placeholder)
|
||||||
|
// }
|
||||||
|
// ),
|
||||||
|
// contentDescription = ""
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
// AndroidView(
|
||||||
|
// modifier = modifier,
|
||||||
|
// factory = { context ->
|
||||||
|
// val p = YouTubePlayerView(context).apply {
|
||||||
|
// var player: YouTubePlayer? = null
|
||||||
|
//// lifecyclerOwner.lifecycle.addObserver(this)
|
||||||
|
// addYouTubePlayerListener(object : AbstractYouTubePlayerListener() {
|
||||||
|
// override fun onReady(youTubePlayer: YouTubePlayer) {
|
||||||
|
// player = youTubePlayer
|
||||||
|
// youTubePlayer.loadVideo(key, 0f)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// addFullScreenListener(object : YouTubePlayerFullScreenListener {
|
||||||
|
// override fun onYouTubePlayerEnterFullScreen() {
|
||||||
|
// player?.play()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// override fun onYouTubePlayerExitFullScreen() {
|
||||||
|
// showFullscreenView.value = false
|
||||||
|
// player?.pause()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// p.enterFullScreen()
|
||||||
|
//
|
||||||
|
// p
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -188,7 +188,9 @@ private fun ContentColumn(
|
|||||||
|
|
||||||
CastCard(itemId = itemId, service = service, modifier = Modifier.padding(bottom = 16.dp))
|
CastCard(itemId = itemId, service = service, modifier = Modifier.padding(bottom = 16.dp))
|
||||||
|
|
||||||
SimilarContent(itemId = itemId, service = service)//, modifier = Modifier.padding(bottom = 16.dp))
|
SimilarContentCard(itemId = itemId, service = service, modifier = Modifier.padding(bottom = 16.dp))
|
||||||
|
|
||||||
|
VideosCard(itemId = itemId, service = service)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +338,7 @@ private fun CastCrewCard(person: Person) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SimilarContent(itemId: Int?, service: DetailService, modifier: Modifier = Modifier) {
|
fun SimilarContentCard(itemId: Int?, service: DetailService, modifier: Modifier = Modifier) {
|
||||||
val similarContent = remember { mutableStateOf<HomePageResponse?>(null) }
|
val similarContent = remember { mutableStateOf<HomePageResponse?>(null) }
|
||||||
itemId?.let {
|
itemId?.let {
|
||||||
if (similarContent.value == null) {
|
if (similarContent.value == null) {
|
||||||
@@ -368,6 +370,54 @@ fun SimilarContent(itemId: Int?, service: DetailService, modifier: Modifier = Mo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun VideosCard(itemId: Int?, service: DetailService, modifier: Modifier = Modifier) {
|
||||||
|
val videoResponse = remember { mutableStateOf<VideoResponse?>(null) }
|
||||||
|
itemId?.let {
|
||||||
|
if (videoResponse.value == null) {
|
||||||
|
fetchVideos(itemId, service, videoResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentCard(
|
||||||
|
modifier = modifier,
|
||||||
|
title = "Trailers"
|
||||||
|
) {
|
||||||
|
LazyRow(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.wrapContentHeight()
|
||||||
|
.padding(vertical = 12.dp, horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
val videos = videoResponse.value?.results?.filter { it.isOfficial && it.type.lowercase() in listOf("trailer"/*, "teaser"*/) }
|
||||||
|
val types = videos?.map { it.type }
|
||||||
|
items(videos?.size ?: 0) { i ->
|
||||||
|
val video = videos!![i]
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.wrapContentHeight().width(152.dp)
|
||||||
|
) {
|
||||||
|
FullScreenThumbnailVideoPlayer(
|
||||||
|
key = video.key,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(width = 152.dp, height = 108.dp)
|
||||||
|
.padding(end = 4.dp)
|
||||||
|
)
|
||||||
|
MinLinesText(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 5.dp),
|
||||||
|
minLines = 2,
|
||||||
|
text = video.name,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun fetchMediaItem(id: Int, service: DetailService, mediaItem: MutableState<DetailedItem?>) {
|
private fun fetchMediaItem(id: Int, service: DetailService, mediaItem: MutableState<DetailedItem?>) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
val response = service.getById(id)
|
val response = service.getById(id)
|
||||||
@@ -435,3 +485,14 @@ private fun fetchSimilarContent(id: Int, service: DetailService, similarContent:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun fetchVideos(id: Int, service: DetailService, videoResponse: MutableState<VideoResponse?>) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val results = service.getVideos(id)
|
||||||
|
if (results.isSuccessful) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
videoResponse.value = results.body()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
package com.owenlejeune.tvtime.utils
|
package com.owenlejeune.tvtime.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.SparseArray
|
||||||
import androidx.compose.ui.text.intl.Locale
|
import androidx.compose.ui.text.intl.Locale
|
||||||
|
import at.huber.youtubeExtractor.VideoMeta
|
||||||
|
import at.huber.youtubeExtractor.YouTubeExtractor
|
||||||
|
import at.huber.youtubeExtractor.YtFile
|
||||||
import com.owenlejeune.tvtime.api.tmdb.model.*
|
import com.owenlejeune.tvtime.api.tmdb.model.*
|
||||||
|
|
||||||
object TmdbUtils {
|
object TmdbUtils {
|
||||||
@@ -133,4 +138,20 @@ object TmdbUtils {
|
|||||||
return detailItem.voteAverage / 10f
|
return detailItem.voteAverage / 10f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getFullVideoUrl(video: Video): String {
|
||||||
|
// object: YouTubeExtractor(context) {
|
||||||
|
// override fun onExtractionComplete(
|
||||||
|
// ytFiles: SparseArray<YtFile>?,
|
||||||
|
// videoMeta: VideoMeta?
|
||||||
|
// ) {
|
||||||
|
// if (ytFiles != null) {
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (video.site == "YouTube") {
|
||||||
|
return "http://www.youtube.com/watch?v=${video.key}"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ buildscript {
|
|||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
|
||||||
@@ -14,6 +15,7 @@ subprojects {
|
|||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ pluginManagement {
|
|||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
@@ -10,6 +11,7 @@ dependencyResolutionManagement {
|
|||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rootProject.name = "TVTime"
|
rootProject.name = "TVTime"
|
||||||
|
|||||||
Reference in New Issue
Block a user