From dcaf64acde396a2d9223db634454b528606d2773 Mon Sep 17 00:00:00 2001 From: Jannik Date: Tue, 13 Oct 2020 15:56:07 +0200 Subject: [PATCH] improved MediaFragment UI * fix searchview not losing focus when media is selected --- .../java/org/mosad/teapod/MainActivity.kt | 7 ++- .../java/org/mosad/teapod/parser/AoDParser.kt | 25 ++++++++-- .../java/org/mosad/teapod/ui/MediaFragment.kt | 16 ++++-- .../mosad/teapod/ui/search/SearchFragment.kt | 13 +++-- .../java/org/mosad/teapod/util/DataTypes.kt | 8 +-- .../org/mosad/teapod/util/EpisodesAdapter.kt | 12 +++-- .../mosad/teapod/util/TMDBApiController.kt | 26 +++++++++- .../res/drawable/shape_rounden_corner.xml | 5 ++ app/src/main/res/layout/component_episode.xml | 6 +-- app/src/main/res/layout/fragment_media.xml | 50 ++++++++++++++++--- app/src/main/res/values-de-rDE/strings.xml | 2 + app/src/main/res/values/strings.xml | 4 ++ 12 files changed, 139 insertions(+), 35 deletions(-) create mode 100644 app/src/main/res/drawable/shape_rounden_corner.xml diff --git a/app/src/main/java/org/mosad/teapod/MainActivity.kt b/app/src/main/java/org/mosad/teapod/MainActivity.kt index 16fdf55..7546e86 100644 --- a/app/src/main/java/org/mosad/teapod/MainActivity.kt +++ b/app/src/main/java/org/mosad/teapod/MainActivity.kt @@ -9,6 +9,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.fragment.app.commit import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch import org.mosad.teapod.parser.AoDParser import org.mosad.teapod.preferences.EncryptedPreferences import org.mosad.teapod.ui.MediaFragment @@ -84,7 +86,10 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS } } - fun showDetailFragment(media: Media) { + /** + * TODO show loading fragment + */ + fun showDetailFragment(media: Media) = GlobalScope.launch { media.episodes = AoDParser().loadStreams(media) // load the streams for the selected media val tmdb = TMDBApiController().search(media.title, media.type) diff --git a/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt b/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt index 55b6655..554e5dc 100644 --- a/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt +++ b/app/src/main/java/org/mosad/teapod/parser/AoDParser.kt @@ -36,10 +36,10 @@ class AoDParser { .execute() val authenticityToken = resAuth.parse().select("meta[name=csrf-token]").attr("content") - println("Authenticity token is: $authenticityToken") + val authCookies = resAuth.cookies() - val cookies = resAuth.cookies() - println("cookies: $cookies") + Log.i(javaClass.name, "Received authenticity token: $authenticityToken") + Log.i(javaClass.name, "Received authenticity cookies: $authCookies") val data = mapOf( Pair("user[login]", EncryptedPreferences.login), @@ -53,7 +53,7 @@ class AoDParser { .method(Connection.Method.POST) .data(data) .postDataCharset("UTF-8") - .cookies(cookies) + .cookies(authCookies) .execute() //println(resLogin.body()) @@ -122,6 +122,15 @@ class AoDParser { //println(res) + // parse additional info from the media page + res.select("table.vertical-table").select("tr").forEach { + when (it.select("th").text().toLowerCase(Locale.ROOT)) { + "produktionsjahr" -> media.info.year = it.select("td").text().toInt() + "fsk" -> media.info.age = it.select("td").text().toInt() + "episodenanzahl" -> media.info.episodesCount = it.select("td").text().toInt() + } + } + val playlists = res.select("input.streamstarter_html5").eachAttr("data-playlist") val csrfToken = res.select("meta[name=csrf-token]").attr("content") @@ -176,10 +185,16 @@ class AoDParser { .first().asJsonObject .get("file").asString val episodeTitle = it.asJsonObject.get("title").asString + val episodePoster = it.asJsonObject.get("image").asString + val episodeDescription = it.asJsonObject.get("description").asString + val episodeNumber = episodeTitle.substringAfter(", Ep. ").toInt() Episode( episodeTitle, - episodeStream + episodeStream, + episodePoster, + episodeDescription, + episodeNumber ) } diff --git a/app/src/main/java/org/mosad/teapod/ui/MediaFragment.kt b/app/src/main/java/org/mosad/teapod/ui/MediaFragment.kt index 6d3420b..10ffc71 100644 --- a/app/src/main/java/org/mosad/teapod/ui/MediaFragment.kt +++ b/app/src/main/java/org/mosad/teapod/ui/MediaFragment.kt @@ -55,20 +55,26 @@ class MediaFragment(private val media: Media, private val tmdb: TMDBResponse) : .into(image_poster) text_title.text = media.title - // TODO add year, fsk - text_overview.text = if (tmdb.overview.isNotEmpty()) tmdb.overview else media.shortDesc + text_year.text = media.info.year.toString() + text_age.text = media.info.age.toString() + text_overview.text = media.shortDesc //if (tmdb.overview.isNotEmpty()) tmdb.overview else media.shortDesc // specific gui if (media.type == MediaType.TVSHOW) { - val episodeTitles = media.episodes.map { it.title } - - adapterRecEpisodes = EpisodesAdapter(episodeTitles) + adapterRecEpisodes = EpisodesAdapter(media.episodes, requireContext()) viewManager = LinearLayoutManager(context) recycler_episodes.layoutManager = viewManager recycler_episodes.adapter = adapterRecEpisodes + text_episodes_or_runtime.text = getString(R.string.text_episodes_count, media.info.episodesCount) } else if (media.type == MediaType.MOVIE) { recycler_episodes.visibility = View.GONE + + if (tmdb.runtime > 0) { + text_episodes_or_runtime.text = getString(R.string.text_runtime, tmdb.runtime) + } else { + text_episodes_or_runtime.visibility = View.GONE + } } } diff --git a/app/src/main/java/org/mosad/teapod/ui/search/SearchFragment.kt b/app/src/main/java/org/mosad/teapod/ui/search/SearchFragment.kt index c0db7d0..847ef48 100644 --- a/app/src/main/java/org/mosad/teapod/ui/search/SearchFragment.kt +++ b/app/src/main/java/org/mosad/teapod/ui/search/SearchFragment.kt @@ -16,7 +16,6 @@ import org.mosad.teapod.util.Media class SearchFragment : Fragment() { - private val instance = this private lateinit var adapter : CustomAdapter override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -46,6 +45,8 @@ class SearchFragment : Fragment() { private fun initActions() { search_text.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { + adapter.filter.filter(query) + adapter.notifyDataSetChanged() return false } @@ -57,12 +58,14 @@ class SearchFragment : Fragment() { }) list_search.setOnItemClickListener { _, _, position, _ -> - val media = adapter.getItem(position) as Media + search_text.clearFocus() // remove focus from the SearchView - println("selected item is: ${media.title}") + runBlocking { + val media = adapter.getItem(position) as Media + println("selected item is: ${media.title}") - val mainActivity = activity as MainActivity - mainActivity.showDetailFragment(media) + (activity as MainActivity).showDetailFragment(media).join() + } } } } \ No newline at end of file diff --git a/app/src/main/java/org/mosad/teapod/util/DataTypes.kt b/app/src/main/java/org/mosad/teapod/util/DataTypes.kt index e3610b2..f3616e5 100644 --- a/app/src/main/java/org/mosad/teapod/util/DataTypes.kt +++ b/app/src/main/java/org/mosad/teapod/util/DataTypes.kt @@ -8,12 +8,14 @@ class DataTypes { } } -data class Media(val title: String, val link: String, val type: DataTypes.MediaType, val posterLink: String, val shortDesc : String, var episodes: List = listOf()) { +data class Media(val title: String, val link: String, val type: DataTypes.MediaType, val posterLink: String, val shortDesc : String, var episodes: List = listOf(), val info : Info = Info()) { override fun toString(): String { return title } } -data class Episode(val title: String = "", val streamUrl: String = "", val posterLink: String = "", var watched: Boolean = false) +data class Info(var description: String = "", var year: Int = 0, var age: Int = 0, var episodesCount: Int = 0) -data class TMDBResponse(val title: String = "", val overview: String = "", val posterUrl: String = "", val backdropUrl: String = "") +data class Episode(val title: String = "", val streamUrl: String = "", val posterLink: String = "", var description: String = "", var number: Int = 0, var watched: Boolean = false) + +data class TMDBResponse(val id: Int = 0, val title: String = "", val overview: String = "", val posterUrl: String = "", val backdropUrl: String = "", var runtime: Int = 0) diff --git a/app/src/main/java/org/mosad/teapod/util/EpisodesAdapter.kt b/app/src/main/java/org/mosad/teapod/util/EpisodesAdapter.kt index 347017b..e271226 100644 --- a/app/src/main/java/org/mosad/teapod/util/EpisodesAdapter.kt +++ b/app/src/main/java/org/mosad/teapod/util/EpisodesAdapter.kt @@ -1,13 +1,15 @@ package org.mosad.teapod.util +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.component_episode.view.* import org.mosad.teapod.R -class EpisodesAdapter(private val data: List) : RecyclerView.Adapter() { +class EpisodesAdapter(private val data: List, private val context: Context) : RecyclerView.Adapter() { var onItemClick: ((String, Int) -> Unit)? = null @@ -18,7 +20,11 @@ class EpisodesAdapter(private val data: List) : RecyclerView.Adapter) : RecyclerView.Adapter 0) { response.get("results").asJsonArray.first().asJsonObject.let { + val id = getStringNotNull(it,"id").toInt() val overview = getStringNotNull(it,"overview") val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl) val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl) - TMDBResponse("", overview, posterPath, backdropPath) + TMDBResponse(id, "", overview, posterPath, backdropPath) } } else { TMDBResponse() @@ -66,11 +68,13 @@ class TMDBApiController { return@async if (response.get("total_results").asInt > 0) { response.get("results").asJsonArray.first().asJsonObject.let { + val id = getStringNotNull(it,"id").toInt() val overview = getStringNotNull(it,"overview") val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl) val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl) + val runtime = getMovieRuntime(id) - TMDBResponse("", overview, posterPath, backdropPath) + TMDBResponse(id, "", overview, posterPath, backdropPath, runtime) } } else { TMDBResponse() @@ -80,6 +84,24 @@ class TMDBApiController { }.await() } + /** + * currently only used for runtime, need a rework + */ + fun getMovieRuntime(id: Int): Int = runBlocking { + val url = URL("$getMovieUrl/$id?api_key=$apiKey&language=$language") + + GlobalScope.async { + val response = JsonParser.parseString(url.readText()).asJsonObject + //println(response) + + val runtime = getStringNotNull(response,"runtime").toInt() + println(runtime) + + + return@async runtime + }.await() + } + /** * return memberName as string if it's not JsonNull, * else return an empty string diff --git a/app/src/main/res/drawable/shape_rounden_corner.xml b/app/src/main/res/drawable/shape_rounden_corner.xml new file mode 100644 index 0000000..ca4ac44 --- /dev/null +++ b/app/src/main/res/drawable/shape_rounden_corner.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/component_episode.xml b/app/src/main/res/layout/component_episode.xml index f9da4c3..b02a8f5 100644 --- a/app/src/main/res/layout/component_episode.xml +++ b/app/src/main/res/layout/component_episode.xml @@ -16,10 +16,8 @@ + android:orientation="vertical"> + + + + + + + + + Abspielen + %1$d Episoden + %1$d Minuten Account diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 19a7e1b..0176503 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -12,6 +12,10 @@ Play A Silent Voice Shouya Ishida starts bullying the new girl in class … + 2016 + 6 + %1$d episodes + %1$d Minutes Account