show loading screen while loading media fragment
* use material components for shaped images and progress indicator
This commit is contained in:
parent
d2728405d1
commit
5f80f1fabd
@ -46,7 +46,7 @@ dependencies {
|
|||||||
implementation 'androidx.security:security-crypto:1.1.0-alpha02'
|
implementation 'androidx.security:security-crypto:1.1.0-alpha02'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
|
|
||||||
implementation 'com.google.android.material:material:1.2.1'
|
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||||
implementation 'com.google.code.gson:gson:2.8.6'
|
implementation 'com.google.code.gson:gson:2.8.6'
|
||||||
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.0'
|
implementation 'com.google.android.exoplayer:exoplayer-core:2.12.0'
|
||||||
implementation 'com.google.android.exoplayer:exoplayer-hls:2.12.0'
|
implementation 'com.google.android.exoplayer:exoplayer-hls:2.12.0'
|
||||||
|
@ -32,6 +32,7 @@ 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.GlobalScope
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.launch
|
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
|
||||||
@ -41,8 +42,7 @@ import org.mosad.teapod.ui.components.LoginDialog
|
|||||||
import org.mosad.teapod.ui.home.HomeFragment
|
import org.mosad.teapod.ui.home.HomeFragment
|
||||||
import org.mosad.teapod.ui.library.LibraryFragment
|
import org.mosad.teapod.ui.library.LibraryFragment
|
||||||
import org.mosad.teapod.ui.search.SearchFragment
|
import org.mosad.teapod.ui.search.SearchFragment
|
||||||
import org.mosad.teapod.util.Media
|
import org.mosad.teapod.util.*
|
||||||
import org.mosad.teapod.util.TMDBApiController
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {
|
class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemSelectedListener {
|
||||||
|
|
||||||
@ -70,6 +70,10 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
override fun onNavigationItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (supportFragmentManager.backStackEntryCount > 0) {
|
||||||
|
supportFragmentManager.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
val ret = when (item.itemId) {
|
val ret = when (item.itemId) {
|
||||||
R.id.navigation_home -> {
|
R.id.navigation_home -> {
|
||||||
activeFragment = HomeFragment()
|
activeFragment = HomeFragment()
|
||||||
@ -109,11 +113,18 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO show loading fragment
|
* show the media fragment for the selected media
|
||||||
|
* while loading show the loading fragment
|
||||||
*/
|
*/
|
||||||
fun showDetailFragment(media: Media) = GlobalScope.launch {
|
fun showMediaFragment(media: Media) = GlobalScope.launch {
|
||||||
media.episodes = AoDParser().loadStreams(media) // load the streams for the selected media
|
val loadingFragment = LoadingFragment()
|
||||||
|
supportFragmentManager.commit {
|
||||||
|
add(R.id.nav_host_fragment, loadingFragment, "MediaFragment")
|
||||||
|
show(loadingFragment)
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the streams for the selected media
|
||||||
|
media.episodes = AoDParser().loadStreams(media)
|
||||||
val tmdb = TMDBApiController().search(media.title, media.type)
|
val tmdb = TMDBApiController().search(media.title, media.type)
|
||||||
|
|
||||||
val mediaFragment = MediaFragment(media, tmdb)
|
val mediaFragment = MediaFragment(media, tmdb)
|
||||||
@ -122,6 +133,10 @@ class MainActivity : AppCompatActivity(), BottomNavigationView.OnNavigationItemS
|
|||||||
addToBackStack(null)
|
addToBackStack(null)
|
||||||
show(mediaFragment)
|
show(mediaFragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
supportFragmentManager.commit {
|
||||||
|
remove(loadingFragment)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startPlayer(streamUrl: String) {
|
fun startPlayer(streamUrl: String) {
|
||||||
|
@ -19,13 +19,13 @@ import org.mosad.teapod.MainActivity
|
|||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
import org.mosad.teapod.parser.AoDParser
|
import org.mosad.teapod.parser.AoDParser
|
||||||
import org.mosad.teapod.util.DataTypes.MediaType
|
import org.mosad.teapod.util.DataTypes.MediaType
|
||||||
import org.mosad.teapod.util.EpisodesAdapter
|
import org.mosad.teapod.util.adapter.EpisodeItemAdapter
|
||||||
import org.mosad.teapod.util.Media
|
import org.mosad.teapod.util.Media
|
||||||
import org.mosad.teapod.util.TMDBResponse
|
import org.mosad.teapod.util.TMDBResponse
|
||||||
|
|
||||||
class MediaFragment(private val media: Media, private val tmdb: TMDBResponse) : Fragment() {
|
class MediaFragment(private val media: Media, private val tmdb: TMDBResponse) : Fragment() {
|
||||||
|
|
||||||
private lateinit var adapterRecEpisodes: EpisodesAdapter
|
private lateinit var adapterRecEpisodes: EpisodeItemAdapter
|
||||||
private lateinit var viewManager: RecyclerView.LayoutManager
|
private lateinit var viewManager: RecyclerView.LayoutManager
|
||||||
|
|
||||||
|
|
||||||
@ -55,17 +55,16 @@ class MediaFragment(private val media: Media, private val tmdb: TMDBResponse) :
|
|||||||
.into(image_backdrop)
|
.into(image_backdrop)
|
||||||
|
|
||||||
Glide.with(requireContext()).load(posterUrl)
|
Glide.with(requireContext()).load(posterUrl)
|
||||||
.apply(RequestOptions.bitmapTransform(RoundedCornersTransformation(posterCornerRadius, 0)))
|
|
||||||
.into(image_poster)
|
.into(image_poster)
|
||||||
|
|
||||||
text_title.text = media.title
|
text_title.text = media.title
|
||||||
text_year.text = media.info.year.toString()
|
text_year.text = media.info.year.toString()
|
||||||
text_age.text = media.info.age.toString()
|
text_age.text = media.info.age.toString()
|
||||||
text_overview.text = media.info.shortDesc //if (tmdb.overview.isNotEmpty()) tmdb.overview else media.shortDesc
|
text_overview.text = media.info.shortDesc
|
||||||
|
|
||||||
// specific gui
|
// specific gui
|
||||||
if (media.type == MediaType.TVSHOW) {
|
if (media.type == MediaType.TVSHOW) {
|
||||||
adapterRecEpisodes = EpisodesAdapter(media.episodes, requireContext())
|
adapterRecEpisodes = EpisodeItemAdapter(media.episodes, requireContext())
|
||||||
viewManager = LinearLayoutManager(context)
|
viewManager = LinearLayoutManager(context)
|
||||||
recycler_episodes.layoutManager = viewManager
|
recycler_episodes.layoutManager = viewManager
|
||||||
recycler_episodes.adapter = adapterRecEpisodes
|
recycler_episodes.adapter = adapterRecEpisodes
|
||||||
|
@ -6,17 +6,16 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import kotlinx.android.synthetic.main.fragment_library.*
|
import kotlinx.android.synthetic.main.fragment_library.*
|
||||||
import kotlinx.android.synthetic.main.item_media.view.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.mosad.teapod.MainActivity
|
import org.mosad.teapod.MainActivity
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
import org.mosad.teapod.parser.AoDParser
|
import org.mosad.teapod.parser.AoDParser
|
||||||
import org.mosad.teapod.util.CustomAdapter
|
import org.mosad.teapod.util.adapter.MediaItemAdapter
|
||||||
import org.mosad.teapod.util.Media
|
import org.mosad.teapod.util.Media
|
||||||
|
|
||||||
class LibraryFragment : Fragment() {
|
class LibraryFragment : Fragment() {
|
||||||
|
|
||||||
private lateinit var adapter : CustomAdapter
|
private lateinit var adapter : MediaItemAdapter
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_library, container, false)
|
return inflater.inflate(R.layout.fragment_library, container, false)
|
||||||
@ -33,7 +32,7 @@ class LibraryFragment : Fragment() {
|
|||||||
// create and set the adapter, needs context
|
// create and set the adapter, needs context
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
context?.let {
|
context?.let {
|
||||||
adapter = CustomAdapter(it, AoDParser.mediaList)
|
adapter = MediaItemAdapter(it, AoDParser.mediaList)
|
||||||
grid_media_library.adapter = adapter
|
grid_media_library.adapter = adapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,7 +46,7 @@ class LibraryFragment : Fragment() {
|
|||||||
val media = adapter.getItem(position) as Media
|
val media = adapter.getItem(position) as Media
|
||||||
println("selected item is: ${media.title}")
|
println("selected item is: ${media.title}")
|
||||||
|
|
||||||
(activity as MainActivity).showDetailFragment(media)
|
(activity as MainActivity).showMediaFragment(media)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,12 +11,12 @@ import kotlinx.coroutines.*
|
|||||||
import org.mosad.teapod.MainActivity
|
import org.mosad.teapod.MainActivity
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
import org.mosad.teapod.parser.AoDParser
|
import org.mosad.teapod.parser.AoDParser
|
||||||
import org.mosad.teapod.util.CustomAdapter
|
import org.mosad.teapod.util.adapter.MediaItemAdapter
|
||||||
import org.mosad.teapod.util.Media
|
import org.mosad.teapod.util.Media
|
||||||
|
|
||||||
class SearchFragment : Fragment() {
|
class SearchFragment : Fragment() {
|
||||||
|
|
||||||
private var adapter : CustomAdapter? = null
|
private var adapter : MediaItemAdapter? = null
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_search, container, false)
|
return inflater.inflate(R.layout.fragment_search, container, false)
|
||||||
@ -33,7 +33,7 @@ class SearchFragment : Fragment() {
|
|||||||
// create and set the adapter, needs context
|
// create and set the adapter, needs context
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
context?.let {
|
context?.let {
|
||||||
adapter = CustomAdapter(it, AoDParser.mediaList)
|
adapter = MediaItemAdapter(it, AoDParser.mediaList)
|
||||||
grid_media_search.adapter = adapter
|
grid_media_search.adapter = adapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,12 +60,10 @@ class SearchFragment : Fragment() {
|
|||||||
grid_media_search.setOnItemClickListener { _, _, position, _ ->
|
grid_media_search.setOnItemClickListener { _, _, position, _ ->
|
||||||
search_text.clearFocus() // remove focus from the SearchView
|
search_text.clearFocus() // remove focus from the SearchView
|
||||||
|
|
||||||
runBlocking {
|
val media = adapter?.getItem(position) as Media
|
||||||
val media = adapter?.getItem(position) as Media
|
println("selected item is: ${media.title}")
|
||||||
println("selected item is: ${media.title}")
|
|
||||||
|
|
||||||
(activity as MainActivity).showDetailFragment(media).join()
|
(activity as MainActivity).showMediaFragment(media)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
16
app/src/main/java/org/mosad/teapod/util/LoadingFragment.kt
Normal file
16
app/src/main/java/org/mosad/teapod/util/LoadingFragment.kt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package org.mosad.teapod.util
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import org.mosad.teapod.R
|
||||||
|
|
||||||
|
class LoadingFragment : Fragment() {
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_loading, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package org.mosad.teapod.util
|
package org.mosad.teapod.util.adapter
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -10,8 +10,9 @@ import com.bumptech.glide.request.RequestOptions
|
|||||||
import jp.wasabeef.glide.transformations.RoundedCornersTransformation
|
import jp.wasabeef.glide.transformations.RoundedCornersTransformation
|
||||||
import kotlinx.android.synthetic.main.item_episode.view.*
|
import kotlinx.android.synthetic.main.item_episode.view.*
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
|
import org.mosad.teapod.util.Episode
|
||||||
|
|
||||||
class EpisodesAdapter(private val episodes: List<Episode>, private val context: Context) : RecyclerView.Adapter<EpisodesAdapter.MyViewHolder>() {
|
class EpisodeItemAdapter(private val episodes: List<Episode>, private val context: Context) : RecyclerView.Adapter<EpisodeItemAdapter.MyViewHolder>() {
|
||||||
|
|
||||||
var onItemClick: ((String, Int) -> Unit)? = null
|
var onItemClick: ((String, Int) -> Unit)? = null
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.mosad.teapod.util
|
package org.mosad.teapod.util.adapter
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@ -7,9 +7,10 @@ import android.view.ViewGroup
|
|||||||
import android.widget.*
|
import android.widget.*
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
|
import org.mosad.teapod.util.Media
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class CustomAdapter(val context: Context, private val originalMedia: ArrayList<Media>) : BaseAdapter(), Filterable {
|
class MediaItemAdapter(val context: Context, private val originalMedia: ArrayList<Media>) : BaseAdapter(), Filterable {
|
||||||
|
|
||||||
private var filteredMedia = originalMedia.map { it.copy() }
|
private var filteredMedia = originalMedia.map { it.copy() }
|
||||||
private val customFilter = CustomFilter()
|
private val customFilter = CustomFilter()
|
@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
@ -15,10 +14,12 @@
|
|||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
<!-- app:controller_layout_id="@layout/player_custom_control"/>-->
|
<!-- app:controller_layout_id="@layout/player_custom_control"/>-->
|
||||||
|
|
||||||
<ProgressBar
|
<com.google.android.material.progressindicator.ProgressIndicator
|
||||||
android:id="@+id/loading"
|
android:id="@+id/loading"
|
||||||
|
style="@style/Widget.MaterialComponents.ProgressIndicator.Circular.Indeterminate"
|
||||||
android:layout_width="70dp"
|
android:layout_width="70dp"
|
||||||
android:layout_height="70dp"
|
android:layout_height="70dp"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
17
app/src/main/res/layout/fragment_loading.xml
Normal file
17
app/src/main/res/layout/fragment_loading.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#f5f5f5"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true">
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.ProgressIndicator
|
||||||
|
android:id="@+id/progressBar2"
|
||||||
|
style="@style/Widget.MaterialComponents.ProgressIndicator.Circular.Indeterminate"
|
||||||
|
android:layout_width="70dp"
|
||||||
|
android:layout_height="70dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
</FrameLayout>
|
@ -30,12 +30,13 @@
|
|||||||
android:minHeight="220dp"
|
android:minHeight="220dp"
|
||||||
android:scaleType="centerCrop" />
|
android:scaleType="centerCrop" />
|
||||||
|
|
||||||
<ImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/image_poster"
|
android:id="@+id/image_poster"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:src="@drawable/ic_launcher_background" />
|
app:shapeAppearance="@style/ShapeAppearance.Teapod.RoundedPoster"
|
||||||
|
app:srcCompat="@drawable/ic_launcher_background" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
@ -14,12 +14,13 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/image_episode"
|
android:id="@+id/image_episode"
|
||||||
android:layout_width="128dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="72dp"
|
android:layout_height="72dp"
|
||||||
android:contentDescription="@string/component_poster_desc"
|
android:contentDescription="@string/component_poster_desc"
|
||||||
app:srcCompat="@color/md_disabled_text_dark_theme" />
|
app:srcCompat="@color/md_disabled_text_dark_theme"
|
||||||
|
app:shapeAppearance="@style/ShapeAppearance.Teapod.RoundedPoster"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text_episode_title"
|
android:id="@+id/text_episode_title"
|
||||||
|
@ -14,5 +14,10 @@
|
|||||||
<item name="android:windowContentOverlay">@null</item>
|
<item name="android:windowContentOverlay">@null</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- shapes -->
|
||||||
|
<style name="ShapeAppearance.Teapod.RoundedPoster" parent="ShapeAppearance.MaterialComponents.LargeComponent">
|
||||||
|
<item name="cornerFamily">rounded</item>
|
||||||
|
<item name="cornerSize">5dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue
Block a user