8 Commits

10 changed files with 90 additions and 61 deletions

View File

@ -12,8 +12,8 @@ android {
applicationId "org.mosad.teapod"
minSdkVersion 23
targetSdkVersion 32
versionCode 9020 //00.09.020
versionName "1.0.0-beta3"
versionCode 100000 //01.00.000
versionName "1.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "build_time", buildTime()

View File

@ -39,13 +39,13 @@ import com.facebook.shimmer.ShimmerFrameLayout
import kotlinx.coroutines.launch
import org.mosad.teapod.R
import org.mosad.teapod.databinding.FragmentHomeBinding
import org.mosad.teapod.ui.activity.main.MainActivity
import org.mosad.teapod.ui.activity.main.viewmodel.HomeViewModel
import org.mosad.teapod.util.adapter.MediaEpisodeListAdapter
import org.mosad.teapod.util.adapter.MediaItemListAdapter
import org.mosad.teapod.util.decoration.MediaItemDecoration
import org.mosad.teapod.util.setDrawableTop
import org.mosad.teapod.util.showFragment
import org.mosad.teapod.util.startPlayer
import org.mosad.teapod.util.toItemMediaList
class HomeFragment : Fragment() {
@ -70,10 +70,7 @@ class HomeFragment : Fragment() {
binding.recyclerUpNext.adapter = MediaEpisodeListAdapter(
MediaEpisodeListAdapter.OnClickListener {
val activity = activity
if (activity is MainActivity) {
activity.startPlayer(it.panel.episodeMetadata.seasonId, it.panel.id)
}
activity?.startPlayer(it.panel.episodeMetadata.seasonId, it.panel.id)
}
)
@ -109,16 +106,6 @@ class HomeFragment : Fragment() {
// TODO since this might take a few seconds show a loading animation for the watchlist button
}
binding.buttonPlayHighlight.setOnClickListener {
// TODO implement
lifecycleScope.launch {
//val media = AoDParser.getMediaById(0)
// Log.d(javaClass.name, "Starting Player with mediaId: ${media.aodId}")
//(activity as MainActivity).startPlayer(media.aodId, media.playlist.first().mediaId)
}
}
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
model.onUiState(viewLifecycleOwner.lifecycleScope) { uiState ->
@ -165,7 +152,37 @@ class HomeFragment : Fragment() {
activity?.showFragment(MediaFragment(uiState.highlightItem.id))
}
// disable the shimmer effect and hide the shimmer layouts
binding.buttonPlayHighlight.setOnClickListener {
val panel = uiState.highlightItemUpNext.panel
activity?.startPlayer(panel.episodeMetadata.seasonId, panel.id)
}
// disable the shimmer effect
disableShimmer()
// make highlights layout visible again
binding.linearHighlight.isVisible = true
}
private fun bindUiStateLoading() {
// hide highlights layout
binding.linearHighlight.isVisible = false
println(binding.root.childCount)
binding.root.children.filter { it is ShimmerFrameLayout }.forEach {
it as ShimmerFrameLayout
it.startShimmer()
}
}
private fun bindUiStateError(uiState: HomeViewModel.UiState.Error) {
// currently not used
Log.e(classTag, "A error occurred while loading a UiState: ${uiState.message}")
}
/**
* Disable the shimmer effect for all shimmer layouts and hide them.
*/
private fun disableShimmer() {
binding.shimmerLayoutHighlight.apply {
stopShimmer()
isVisible = false
@ -190,23 +207,6 @@ class HomeFragment : Fragment() {
stopShimmer()
isVisible = false
}
// make highlights layout visible again
binding.linearHighlight.isVisible = true
}
private fun bindUiStateLoading() {
// hide highlights layout
binding.linearHighlight.isVisible = false
binding.root.children.filter { it is ShimmerFrameLayout }.forEach {
it as ShimmerFrameLayout
it.startShimmer()
}
}
private fun bindUiStateError(uiState: HomeViewModel.UiState.Error) {
// currently not used
Log.e(classTag, "A error occurred while loading a UiState: ${uiState.message}")
}
}

View File

@ -44,6 +44,7 @@ class HomeViewModel : ViewModel() {
val recentlyAddedItems: List<Item>,
val topTenItems: List<Item>,
val highlightItem: Item,
val highlightItemUpNext: UpNextSeriesItem,
val highlightIsWatchlist:Boolean
) : UiState()
data class Error(val message: String?) : UiState()
@ -77,12 +78,17 @@ class HomeViewModel : ViewModel() {
val recentlyAddedItems = recentlyAddedJob.await()
// FIXME crashes on newTitles.items.size == 0
val highlightItem = recentlyAddedItems[Random.nextInt(recentlyAddedItems.size)]
val highlightItemIsWatchlist = Crunchyroll.isWatchlist(highlightItem.id)
val highlightItemUpNextJob = viewModelScope.async {
Crunchyroll.upNextSeries(highlightItem.id)
}
val highlightItemIsWatchlistJob = viewModelScope.async {
Crunchyroll.isWatchlist(highlightItem.id)
}
uiState.emit(UiState.Normal(
upNextJob.await(), watchlistJob.await(), recommendationsJob.await(),
recentlyAddedJob.await(), topTenJob.await(), highlightItem,
highlightItemIsWatchlist
highlightItemUpNextJob.await(), highlightItemIsWatchlistJob.await()
))
} catch (e: Exception) {
uiState.emit(UiState.Error(e.message))
@ -115,9 +121,6 @@ class HomeViewModel : ViewModel() {
}
}
}
}
}

View File

@ -9,6 +9,7 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.commit
import org.mosad.teapod.R
import org.mosad.teapod.ui.activity.player.PlayerActivity
import kotlin.system.exitProcess
/**
@ -24,6 +25,20 @@ fun FragmentActivity.showFragment(fragment: Fragment) {
}
}
/**
* Start the player as new activity.
*
* @param seasonId The ID of the season the episode to be played is in
* @param episodeId The ID of the episode to play
*/
fun Activity.startPlayer(seasonId: String, episodeId: String) {
val intent = Intent(this, PlayerActivity::class.java).apply {
putExtra(getString(R.string.intent_season_id), seasonId)
putExtra(getString(R.string.intent_episode_id), episodeId)
}
startActivity(intent)
}
/**
* hide the status and navigation bar
*/

View File

@ -90,7 +90,7 @@ class TMDBApiController {
* NoneTMDBSearchMovie if nothing was found
*/
suspend fun searchMovie(query: String): TMDBSearch<TMDBSearchResultMovie> {
val searchEndpoint = "/search/multi"
val searchEndpoint = "/search/movie"
val parameters = listOf("query" to query, "include_adult" to false)
return try {

View File

@ -32,7 +32,7 @@ import kotlinx.serialization.Serializable
interface TMDBResult {
val id: Int
val name: String
val name: String? // for movies tmdb return string or null
val overview: String? // for movies tmdb return string or null
val posterPath: String?
val backdropPath: String?
@ -40,7 +40,7 @@ interface TMDBResult {
data class TMDBBase(
override val id: Int,
override val name: String,
override val name: String?,
override val overview: String?,
override val posterPath: String?,
override val backdropPath: String?
@ -59,7 +59,7 @@ data class TMDBSearch<T>(
@Serializable
data class TMDBSearchResultMovie(
@SerialName("id") override val id: Int,
@SerialName("title") override val name: String,
@SerialName("title") override val name: String?,
@SerialName("overview") override val overview: String?,
@SerialName("poster_path") override val posterPath: String?,
@SerialName("backdrop_path") override val backdropPath: String?,
@ -68,7 +68,7 @@ data class TMDBSearchResultMovie(
@Serializable
data class TMDBSearchResultTVShow(
@SerialName("id") override val id: Int,
@SerialName("name") override val name: String,
@SerialName("name") override val name: String?,
@SerialName("overview") override val overview: String?,
@SerialName("poster_path") override val posterPath: String?,
@SerialName("backdrop_path") override val backdropPath: String?,
@ -92,7 +92,7 @@ data class TMDBMovie(
@SerialName("release_date") val releaseDate: String,
@SerialName("runtime") val runtime: Int?,
@SerialName("status") val status: String,
// TODO generes
// TODO genres
) : TMDBResult
@Serializable
@ -105,7 +105,7 @@ data class TMDBTVShow(
@SerialName("first_air_date") val firstAirDate: String,
@SerialName("last_air_date") val lastAirDate: String,
@SerialName("status") val status: String,
// TODO generes
// TODO genres
) : TMDBResult
// use null for nullable types, the gui needs to handle/implement a fallback for null values

View File

@ -29,14 +29,14 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/shimmer_image_highlight">
<TextView
android:id="@+id/shimmer_text_highlight_title"
android:layout_width="120dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
<ImageView
android:id="@+id/image_dummy_text"
android:layout_width="128dp"
android:layout_height="21dp"
android:layout_marginTop="7dp"
android:background="?shapeTextBackground"
android:textSize="16sp" />
android:layout_gravity="center"
app:srcCompat="@drawable/shape_rounded_corner"
tools:ignore="ContentDescription" />
<LinearLayout
android:layout_width="match_parent"

View File

@ -19,7 +19,6 @@
android:id="@+id/frame_image_progress"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/text_title"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -35,17 +34,17 @@
</FrameLayout>
<TextView
android:id="@+id/text_title"
<ImageView
android:id="@+id/image_dummy_text"
android:layout_width="128dp"
android:layout_height="wrap_content"
android:layout_height="19dp"
android:layout_margin="11dp"
android:background="?shapeTextBackground"
android:textSize="15sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/frame_image_progress" />
app:layout_constraintTop_toBottomOf="@+id/frame_image_progress"
app:srcCompat="@drawable/shape_rounded_corner"
tools:ignore="ContentDescription" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>

View File

@ -0,0 +1,6 @@
Dies ist der erste stabile Release von Teapod mit Unterstützung für Cunchyroll.
* Unterstützung für Crunchyroll hinzugefügt (Ein premium Account wird benötigt)
* Diverse UI/UX Verbesserungen
Alle Änderungen: https://git.mosad.xyz/Seil0/teapod/compare/0.4.2...1.0.0

View File

@ -0,0 +1,6 @@
This is the first stable release of Teapod with support for crunchyroll.
* Support for crunchyroll (a premium account is needed)
* UI/UX improvements
Full changelog: https://git.mosad.xyz/Seil0/teapod/compare/0.4.2...1.0.0