improved MediaFragment UI
* fix searchview not losing focus when media is selected
This commit is contained in:
		| @ -9,6 +9,8 @@ import androidx.appcompat.app.AppCompatActivity | |||||||
| import androidx.fragment.app.Fragment | import androidx.fragment.app.Fragment | ||||||
| import androidx.fragment.app.commit | import androidx.fragment.app.commit | ||||||
| import kotlinx.android.synthetic.main.activity_main.* | 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.parser.AoDParser | ||||||
| import org.mosad.teapod.preferences.EncryptedPreferences | import org.mosad.teapod.preferences.EncryptedPreferences | ||||||
| import org.mosad.teapod.ui.MediaFragment | 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 |         media.episodes = AoDParser().loadStreams(media) // load the streams for the selected media | ||||||
|  |  | ||||||
|         val tmdb = TMDBApiController().search(media.title, media.type) |         val tmdb = TMDBApiController().search(media.title, media.type) | ||||||
|  | |||||||
| @ -36,10 +36,10 @@ class AoDParser { | |||||||
|                 .execute() |                 .execute() | ||||||
|  |  | ||||||
|             val authenticityToken = resAuth.parse().select("meta[name=csrf-token]").attr("content") |             val authenticityToken = resAuth.parse().select("meta[name=csrf-token]").attr("content") | ||||||
|             println("Authenticity token is: $authenticityToken") |             val authCookies = resAuth.cookies() | ||||||
|  |  | ||||||
|             val cookies = resAuth.cookies() |             Log.i(javaClass.name, "Received authenticity token: $authenticityToken") | ||||||
|             println("cookies: $cookies") |             Log.i(javaClass.name, "Received authenticity cookies: $authCookies") | ||||||
|  |  | ||||||
|             val data = mapOf( |             val data = mapOf( | ||||||
|                 Pair("user[login]", EncryptedPreferences.login), |                 Pair("user[login]", EncryptedPreferences.login), | ||||||
| @ -53,7 +53,7 @@ class AoDParser { | |||||||
|                 .method(Connection.Method.POST) |                 .method(Connection.Method.POST) | ||||||
|                 .data(data) |                 .data(data) | ||||||
|                 .postDataCharset("UTF-8") |                 .postDataCharset("UTF-8") | ||||||
|                 .cookies(cookies) |                 .cookies(authCookies) | ||||||
|                 .execute() |                 .execute() | ||||||
|  |  | ||||||
|             //println(resLogin.body()) |             //println(resLogin.body()) | ||||||
| @ -122,6 +122,15 @@ class AoDParser { | |||||||
|  |  | ||||||
|             //println(res) |             //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 playlists = res.select("input.streamstarter_html5").eachAttr("data-playlist") | ||||||
|             val csrfToken = res.select("meta[name=csrf-token]").attr("content") |             val csrfToken = res.select("meta[name=csrf-token]").attr("content") | ||||||
|  |  | ||||||
| @ -176,10 +185,16 @@ class AoDParser { | |||||||
|                             .first().asJsonObject |                             .first().asJsonObject | ||||||
|                             .get("file").asString |                             .get("file").asString | ||||||
|                         val episodeTitle = it.asJsonObject.get("title").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( |                         Episode( | ||||||
|                             episodeTitle, |                             episodeTitle, | ||||||
|                             episodeStream |                             episodeStream, | ||||||
|  |                             episodePoster, | ||||||
|  |                             episodeDescription, | ||||||
|  |                             episodeNumber | ||||||
|                         ) |                         ) | ||||||
|                     } |                     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -55,20 +55,26 @@ class MediaFragment(private val media: Media, private val tmdb: TMDBResponse) : | |||||||
|             .into(image_poster) |             .into(image_poster) | ||||||
|  |  | ||||||
|         text_title.text = media.title |         text_title.text = media.title | ||||||
|         // TODO add  year, fsk |         text_year.text = media.info.year.toString() | ||||||
|         text_overview.text = if (tmdb.overview.isNotEmpty()) tmdb.overview else media.shortDesc |         text_age.text = media.info.age.toString() | ||||||
|  |         text_overview.text = media.shortDesc //if (tmdb.overview.isNotEmpty()) tmdb.overview else media.shortDesc | ||||||
|  |  | ||||||
|         // specific gui |         // specific gui | ||||||
|         if (media.type == MediaType.TVSHOW) { |         if (media.type == MediaType.TVSHOW) { | ||||||
|             val episodeTitles = media.episodes.map { it.title } |             adapterRecEpisodes = EpisodesAdapter(media.episodes, requireContext()) | ||||||
|  |  | ||||||
|             adapterRecEpisodes = EpisodesAdapter(episodeTitles) |  | ||||||
|             viewManager = LinearLayoutManager(context) |             viewManager = LinearLayoutManager(context) | ||||||
|             recycler_episodes.layoutManager = viewManager |             recycler_episodes.layoutManager = viewManager | ||||||
|             recycler_episodes.adapter = adapterRecEpisodes |             recycler_episodes.adapter = adapterRecEpisodes | ||||||
|  |  | ||||||
|  |             text_episodes_or_runtime.text = getString(R.string.text_episodes_count, media.info.episodesCount) | ||||||
|         } else if (media.type == MediaType.MOVIE) { |         } else if (media.type == MediaType.MOVIE) { | ||||||
|             recycler_episodes.visibility = View.GONE |             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 | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -16,7 +16,6 @@ import org.mosad.teapod.util.Media | |||||||
|  |  | ||||||
| class SearchFragment : Fragment() { | class SearchFragment : Fragment() { | ||||||
|  |  | ||||||
|     private val instance = this |  | ||||||
|     private lateinit var adapter : CustomAdapter |     private lateinit var adapter : CustomAdapter | ||||||
|  |  | ||||||
|     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { |     override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { | ||||||
| @ -46,6 +45,8 @@ class SearchFragment : Fragment() { | |||||||
|     private fun initActions() { |     private fun initActions() { | ||||||
|         search_text.setOnQueryTextListener(object : SearchView.OnQueryTextListener { |         search_text.setOnQueryTextListener(object : SearchView.OnQueryTextListener { | ||||||
|             override fun onQueryTextSubmit(query: String?): Boolean { |             override fun onQueryTextSubmit(query: String?): Boolean { | ||||||
|  |                 adapter.filter.filter(query) | ||||||
|  |                 adapter.notifyDataSetChanged() | ||||||
|                 return false |                 return false | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @ -57,12 +58,14 @@ class SearchFragment : Fragment() { | |||||||
|         }) |         }) | ||||||
|  |  | ||||||
|         list_search.setOnItemClickListener { _, _, position, _ -> |         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 |                 (activity as MainActivity).showDetailFragment(media).join() | ||||||
|             mainActivity.showDetailFragment(media) |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -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<Episode> = listOf()) { | data class Media(val title: String, val link: String, val type: DataTypes.MediaType, val posterLink: String, val shortDesc : String, var episodes: List<Episode> = listOf(), val info : Info = Info()) { | ||||||
|     override fun toString(): String { |     override fun toString(): String { | ||||||
|         return title |         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) | ||||||
|  | |||||||
| @ -1,13 +1,15 @@ | |||||||
| package org.mosad.teapod.util | package org.mosad.teapod.util | ||||||
|  |  | ||||||
|  | import android.content.Context | ||||||
| import android.view.LayoutInflater | import android.view.LayoutInflater | ||||||
| import android.view.View | import android.view.View | ||||||
| import android.view.ViewGroup | import android.view.ViewGroup | ||||||
| import androidx.recyclerview.widget.RecyclerView | import androidx.recyclerview.widget.RecyclerView | ||||||
|  | import com.bumptech.glide.Glide | ||||||
| import kotlinx.android.synthetic.main.component_episode.view.* | import kotlinx.android.synthetic.main.component_episode.view.* | ||||||
| import org.mosad.teapod.R | import org.mosad.teapod.R | ||||||
|  |  | ||||||
| class EpisodesAdapter(private val data: List<String>) : RecyclerView.Adapter<EpisodesAdapter.MyViewHolder>() { | class EpisodesAdapter(private val data: List<Episode>, private val context: Context) : RecyclerView.Adapter<EpisodesAdapter.MyViewHolder>() { | ||||||
|  |  | ||||||
|     var onItemClick: ((String, Int) -> Unit)? = null |     var onItemClick: ((String, Int) -> Unit)? = null | ||||||
|  |  | ||||||
| @ -18,7 +20,11 @@ class EpisodesAdapter(private val data: List<String>) : RecyclerView.Adapter<Epi | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun onBindViewHolder(holder: MyViewHolder, position: Int) { |     override fun onBindViewHolder(holder: MyViewHolder, position: Int) { | ||||||
|         holder.view .text_episode_title.text = data[position] |         holder.view.text_episode_title.text = "Episode ${data[position].number} ${data[position].description}" | ||||||
|  |  | ||||||
|  |         if (data[position].posterLink.isNotEmpty()) { | ||||||
|  |             Glide.with(context).load(data[position].posterLink).into(holder.view.image_episode) | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun getItemCount(): Int { |     override fun getItemCount(): Int { | ||||||
| @ -28,7 +34,7 @@ class EpisodesAdapter(private val data: List<String>) : RecyclerView.Adapter<Epi | |||||||
|     inner class MyViewHolder(val view: View) : RecyclerView.ViewHolder(view) { |     inner class MyViewHolder(val view: View) : RecyclerView.ViewHolder(view) { | ||||||
|         init { |         init { | ||||||
|             view.setOnClickListener { |             view.setOnClickListener { | ||||||
|                 onItemClick?.invoke(data[adapterPosition], adapterPosition) |                 onItemClick?.invoke(data[adapterPosition].title, adapterPosition) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ class TMDBApiController { | |||||||
|     private val apiUrl = "https://api.themoviedb.org/3" |     private val apiUrl = "https://api.themoviedb.org/3" | ||||||
|     private val searchMovieUrl = "$apiUrl/search/movie" |     private val searchMovieUrl = "$apiUrl/search/movie" | ||||||
|     private val searchTVUrl = "$apiUrl/search/tv" |     private val searchTVUrl = "$apiUrl/search/tv" | ||||||
|  |     private val getMovieUrl = "$apiUrl/movie" | ||||||
|     private val apiKey = "de959cf9c07a08b5ca7cb51cda9a40c2" |     private val apiKey = "de959cf9c07a08b5ca7cb51cda9a40c2" | ||||||
|     private val language = "de" |     private val language = "de" | ||||||
|     private val preparedParameters = "?api_key=$apiKey&language=$language" |     private val preparedParameters = "?api_key=$apiKey&language=$language" | ||||||
| @ -44,11 +45,12 @@ class TMDBApiController { | |||||||
|  |  | ||||||
|             return@async if (response.get("total_results").asInt > 0) { |             return@async if (response.get("total_results").asInt > 0) { | ||||||
|                 response.get("results").asJsonArray.first().asJsonObject.let { |                 response.get("results").asJsonArray.first().asJsonObject.let { | ||||||
|  |                     val id = getStringNotNull(it,"id").toInt() | ||||||
|                     val overview = getStringNotNull(it,"overview") |                     val overview = getStringNotNull(it,"overview") | ||||||
|                     val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl) |                     val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl) | ||||||
|                     val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl) |                     val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl) | ||||||
|  |  | ||||||
|                     TMDBResponse("", overview, posterPath, backdropPath) |                     TMDBResponse(id, "", overview, posterPath, backdropPath) | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 TMDBResponse() |                 TMDBResponse() | ||||||
| @ -66,11 +68,13 @@ class TMDBApiController { | |||||||
|  |  | ||||||
|             return@async if (response.get("total_results").asInt > 0) { |             return@async if (response.get("total_results").asInt > 0) { | ||||||
|                 response.get("results").asJsonArray.first().asJsonObject.let { |                 response.get("results").asJsonArray.first().asJsonObject.let { | ||||||
|  |                     val id = getStringNotNull(it,"id").toInt() | ||||||
|                     val overview = getStringNotNull(it,"overview") |                     val overview = getStringNotNull(it,"overview") | ||||||
|                     val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl) |                     val posterPath = getStringNotNullPrefix(it, "poster_path", imageUrl) | ||||||
|                     val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl) |                     val backdropPath = getStringNotNullPrefix(it, "backdrop_path", imageUrl) | ||||||
|  |                     val runtime = getMovieRuntime(id) | ||||||
|  |  | ||||||
|                     TMDBResponse("", overview, posterPath, backdropPath) |                     TMDBResponse(id, "", overview, posterPath, backdropPath, runtime) | ||||||
|                 } |                 } | ||||||
|             } else { |             } else { | ||||||
|                 TMDBResponse() |                 TMDBResponse() | ||||||
| @ -80,6 +84,24 @@ class TMDBApiController { | |||||||
|         }.await() |         }.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, |      * return memberName as string if it's not JsonNull, | ||||||
|      * else return an empty string |      * else return an empty string | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/shape_rounden_corner.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/shape_rounden_corner.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <shape xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <solid android:color="#B0B0B0"/> | ||||||
|  |     <corners android:radius="3dp"/> | ||||||
|  | </shape> | ||||||
| @ -16,10 +16,8 @@ | |||||||
|  |  | ||||||
|         <ImageView |         <ImageView | ||||||
|             android:id="@+id/image_episode" |             android:id="@+id/image_episode" | ||||||
|             android:layout_width="wrap_content" |             android:layout_width="128dp" | ||||||
|             android:layout_height="wrap_content" |             android:layout_height="72dp" | ||||||
|             android:layout_weight="1" |  | ||||||
|             android:minWidth="48dp" |  | ||||||
|             app:srcCompat="@drawable/ic_baseline_account_box_24" /> |             app:srcCompat="@drawable/ic_baseline_account_box_24" /> | ||||||
|  |  | ||||||
|         <TextView |         <TextView | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ | |||||||
|         <LinearLayout |         <LinearLayout | ||||||
|             android:layout_width="match_parent" |             android:layout_width="match_parent" | ||||||
|             android:layout_height="wrap_content" |             android:layout_height="wrap_content" | ||||||
|             android:orientation="vertical" > |             android:orientation="vertical"> | ||||||
|  |  | ||||||
|             <FrameLayout |             <FrameLayout | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
| @ -40,16 +40,52 @@ | |||||||
|  |  | ||||||
|             </FrameLayout> |             </FrameLayout> | ||||||
|  |  | ||||||
|  |             <LinearLayout | ||||||
|  |                 android:id="@+id/linear_media_info" | ||||||
|  |                 android:layout_width="match_parent" | ||||||
|  |                 android:layout_height="wrap_content" | ||||||
|  |                 android:layout_marginTop="10dp" | ||||||
|  |                 android:gravity="center" | ||||||
|  |                 android:orientation="horizontal"> | ||||||
|  |  | ||||||
|  |                 <TextView | ||||||
|  |                     android:id="@+id/text_year" | ||||||
|  |                     android:layout_width="wrap_content" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:padding="2dp" | ||||||
|  |                     android:text="@string/text_year_ex" /> | ||||||
|  |  | ||||||
|  |                 <TextView | ||||||
|  |                     android:id="@+id/text_age" | ||||||
|  |                     android:layout_width="wrap_content" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_marginStart="7dp" | ||||||
|  |                     android:background="@drawable/shape_rounden_corner" | ||||||
|  |                     android:paddingStart="3dp" | ||||||
|  |                     android:paddingTop="2dp" | ||||||
|  |                     android:paddingEnd="3dp" | ||||||
|  |                     android:paddingBottom="2dp" | ||||||
|  |                     android:text="@string/text_age_ex" /> | ||||||
|  |  | ||||||
|  |                 <TextView | ||||||
|  |                     android:id="@+id/text_episodes_or_runtime" | ||||||
|  |                     android:layout_width="wrap_content" | ||||||
|  |                     android:layout_height="wrap_content" | ||||||
|  |                     android:layout_marginStart="7dp" | ||||||
|  |                     android:padding="2dp" | ||||||
|  |                     android:text="@string/text_episodes_count" /> | ||||||
|  |             </LinearLayout> | ||||||
|  |  | ||||||
|             <com.google.android.material.button.MaterialButton |             <com.google.android.material.button.MaterialButton | ||||||
|                 android:id="@+id/button_play" |                 android:id="@+id/button_play" | ||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|                 android:layout_marginStart="7dp" |                 android:layout_marginStart="7dp" | ||||||
|                 android:layout_marginTop="24dp" |                 android:layout_marginTop="6dp" | ||||||
|                 android:layout_marginEnd="7dp" |                 android:layout_marginEnd="7dp" | ||||||
|                 android:gravity="center" |                 android:gravity="center" | ||||||
|                 android:textAllCaps="false" |  | ||||||
|                 android:text="@string/button_play" |                 android:text="@string/button_play" | ||||||
|  |                 android:textAllCaps="false" | ||||||
|                 android:textColor="@android:color/primary_text_dark" |                 android:textColor="@android:color/primary_text_dark" | ||||||
|                 android:textSize="16sp" |                 android:textSize="16sp" | ||||||
|                 app:backgroundTint="#4A4141" |                 app:backgroundTint="#4A4141" | ||||||
| @ -59,7 +95,7 @@ | |||||||
|             <TextView |             <TextView | ||||||
|                 android:id="@+id/text_title" |                 android:id="@+id/text_title" | ||||||
|                 android:layout_width="wrap_content" |                 android:layout_width="wrap_content" | ||||||
|                 android:layout_height="19dp" |                 android:layout_height="wrap_content" | ||||||
|                 android:layout_gravity="center" |                 android:layout_gravity="center" | ||||||
|                 android:layout_marginStart="7dp" |                 android:layout_marginStart="7dp" | ||||||
|                 android:layout_marginTop="12dp" |                 android:layout_marginTop="12dp" | ||||||
| @ -72,9 +108,9 @@ | |||||||
|                 android:layout_width="match_parent" |                 android:layout_width="match_parent" | ||||||
|                 android:layout_height="wrap_content" |                 android:layout_height="wrap_content" | ||||||
|                 android:layout_gravity="center" |                 android:layout_gravity="center" | ||||||
|                 android:layout_marginStart="7dp" |                 android:layout_marginStart="12dp" | ||||||
|                 android:layout_marginTop="10dp" |                 android:layout_marginTop="7dp" | ||||||
|                 android:layout_marginEnd="7dp" |                 android:layout_marginEnd="12dp" | ||||||
|                 android:text="@string/text_overview_ex" /> |                 android:text="@string/text_overview_ex" /> | ||||||
|  |  | ||||||
|             <androidx.recyclerview.widget.RecyclerView |             <androidx.recyclerview.widget.RecyclerView | ||||||
|  | |||||||
| @ -10,6 +10,8 @@ | |||||||
|  |  | ||||||
|     <!-- media fragment --> |     <!-- media fragment --> | ||||||
|     <string name="button_play">Abspielen</string> |     <string name="button_play">Abspielen</string> | ||||||
|  |     <string name="text_episodes_count">%1$d Episoden</string> | ||||||
|  |     <string name="text_runtime">%1$d Minuten</string> | ||||||
|  |  | ||||||
|     <!-- settings fragment --> |     <!-- settings fragment --> | ||||||
|     <string name="account">Account</string> |     <string name="account">Account</string> | ||||||
|  | |||||||
| @ -12,6 +12,10 @@ | |||||||
|     <string name="button_play">Play</string> |     <string name="button_play">Play</string> | ||||||
|     <string name="text_title_ex" translatable="false">A Silent Voice</string> |     <string name="text_title_ex" translatable="false">A Silent Voice</string> | ||||||
|     <string name="text_overview_ex" translatable="false">Shouya Ishida starts bullying the new girl in class …</string> |     <string name="text_overview_ex" translatable="false">Shouya Ishida starts bullying the new girl in class …</string> | ||||||
|  |     <string name="text_year_ex" translatable="false">2016</string> | ||||||
|  |     <string name="text_age_ex" translatable="false">6</string> | ||||||
|  |     <string name="text_episodes_count">%1$d episodes</string> | ||||||
|  |     <string name="text_runtime">%1$d Minutes</string> | ||||||
|  |  | ||||||
|     <!-- settings fragment --> |     <!-- settings fragment --> | ||||||
|     <string name="account">Account</string> |     <string name="account">Account</string> | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user