very nice long hold popups

This commit is contained in:
reduplicated 2023-01-21 23:22:48 +01:00
parent 65fda1889c
commit 60aca3ebdc
8 changed files with 392 additions and 41 deletions

View File

@ -1,16 +1,14 @@
package com.lagradost.cloudstream3
import android.content.ComponentName
import android.content.DialogInterface
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.os.Bundle
import android.util.AttributeSet
import android.util.Log
import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import android.view.*
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.IdRes
@ -19,6 +17,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.NavDestination.Companion.hierarchy
@ -31,6 +30,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.google.android.gms.cast.framework.*
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.navigationrail.NavigationRailView
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import com.lagradost.cloudstream3.APIHolder.allProviders
@ -46,8 +46,7 @@ import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent
import com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.CommonActivity.updateLocale
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.plugins.PluginManager
import com.lagradost.cloudstream3.plugins.PluginManager.loadAllOnlinePlugins
@ -61,9 +60,13 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStri
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.appStringSearch
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.inAppAuths
import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
import com.lagradost.cloudstream3.ui.home.HomeViewModel
import com.lagradost.cloudstream3.ui.result.ResultViewModel2
import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST
import com.lagradost.cloudstream3.ui.result.setImage
import com.lagradost.cloudstream3.ui.result.setText
import com.lagradost.cloudstream3.ui.search.SearchFragment
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
@ -74,6 +77,7 @@ import com.lagradost.cloudstream3.ui.settings.SettingsGeneral
import com.lagradost.cloudstream3.ui.setup.HAS_DONE_SETUP_KEY
import com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.AppUtils.isCastApiAvailable
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
import com.lagradost.cloudstream3.utils.AppUtils.loadRepository
@ -86,9 +90,11 @@ import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.setKey
import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.getResourceColor
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.navigate
@ -96,6 +102,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import com.lagradost.nicehttp.Requests
import com.lagradost.nicehttp.ResponseParser
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.bottom_resultview_preview.*
import kotlinx.android.synthetic.main.fragment_result_swipe.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@ -244,6 +251,10 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
Event<Boolean>() // homepage api, used to speed up time to load for homepage
val afterRepositoryLoadedEvent = Event<Boolean>()
// kinda shitty solution, but cant com main->home otherwise for popups
val bookmarksUpdatedEvent = Event<Boolean>()
/**
* @return true if the str has launched an app task (be it successful or not)
* @param isWebview does not handle providers and opening download page if true. Can still add repos and login.
@ -336,6 +347,16 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}
}
var lastPopup : SearchResponse? = null
fun loadPopup(result: SearchResponse) {
lastPopup = result
viewModel.load(
this, result.url, result.apiName, false, if (getApiDubstatusSettings()
.contains(DubStatus.Dubbed)
) DubStatus.Dubbed else DubStatus.Subbed, null
)
}
override fun onColorSelected(dialogId: Int, color: Int) {
onColorSelectedEvent.invoke(Pair(dialogId, color))
}
@ -619,6 +640,37 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}
}
lateinit var viewModel: ResultViewModel2
override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
viewModel =
ViewModelProvider(this)[ResultViewModel2::class.java]
return super.onCreateView(name, context, attrs)
}
private fun hidePreviewPopupDialog() {
viewModel.clear()
bottomPreviewPopup.dismissSafe(this)
}
var bottomPreviewPopup: BottomSheetDialog? = null
private fun showPreviewPopupDialog(): BottomSheetDialog {
val ret = (bottomPreviewPopup ?: run {
val builder =
BottomSheetDialog(this)
builder.setContentView(R.layout.bottom_resultview_preview)
builder.setOnDismissListener {
bottomPreviewPopup = null
viewModel.clear()
}
builder.setCanceledOnTouchOutside(true)
builder.show()
builder
})
bottomPreviewPopup = ret
return ret
}
override fun onCreate(savedInstanceState: Bundle?) {
app.initClient(this)
@ -708,6 +760,78 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
builder.show().setDefaultFocus()
}
observeNullable(viewModel.page) { resource ->
if (resource == null) {
bottomPreviewPopup.dismissSafe(this)
return@observeNullable
}
when (resource) {
is Resource.Failure -> {
showToast(this, R.string.error)
hidePreviewPopupDialog()
}
is Resource.Loading -> {
showPreviewPopupDialog().apply {
resultview_preview_loading?.isVisible = true
resultview_preview_result?.isVisible = false
resultview_preview_loading_shimmer?.startShimmer()
}
}
is Resource.Success -> {
val d = resource.value
showPreviewPopupDialog().apply {
resultview_preview_loading?.isVisible = false
resultview_preview_result?.isVisible = true
resultview_preview_loading_shimmer?.stopShimmer()
resultview_preview_title?.text = d.title
resultview_preview_meta_type.setText(d.typeText)
resultview_preview_meta_year.setText(d.yearText)
resultview_preview_meta_duration.setText(d.durationText)
resultview_preview_meta_rating.setText(d.ratingText)
resultview_preview_description?.setText(d.plotText)
resultview_preview_poster?.setImage(
d.posterImage ?: d.posterBackgroundImage
)
resultview_preview_poster?.setOnClickListener {
//viewModel.updateWatchStatus(WatchType.PLANTOWATCH)
val value = viewModel.watchStatus.value ?: WatchType.NONE
this@MainActivity.showBottomDialog(
WatchType.values().map { getString(it.stringRes) }.toList(),
value.ordinal,
this@MainActivity.getString(R.string.action_add_to_bookmarks),
showApply = false,
{}) {
viewModel.updateWatchStatus(WatchType.values()[it])
bookmarksUpdatedEvent(true)
}
}
if (!isTvSettings()) // dont want this clickable on tv layout
resultview_preview_description?.setOnClickListener { view ->
view.context?.let { ctx ->
val builder: AlertDialog.Builder =
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
builder.setMessage(d.plotText.asString(ctx).html())
.setTitle(d.plotHeaderText.asString(ctx))
.show()
}
}
resultview_preview_more_info?.setOnClickListener {
hidePreviewPopupDialog()
lastPopup?.let {
loadSearchResult(it)
}
}
}
}
}
}
// ioSafe {
// val plugins =

View File

@ -32,6 +32,7 @@ import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.MainActivity.Companion.bookmarksUpdatedEvent
import com.lagradost.cloudstream3.MainActivity.Companion.mainPluginsLoadedEvent
import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.logError
@ -435,6 +436,11 @@ class HomeFragment : Fragment() {
return inflater.inflate(layout, container, false)
}
override fun onDestroyView() {
bottomSheetDialog?.ownHide()
super.onDestroyView()
}
private fun fixGrid() {
activity?.getSpanCount()?.let {
currentSpan = it
@ -461,14 +467,20 @@ class HomeFragment : Fragment() {
fixGrid()
}
fun bookmarksUpdated(_data : Boolean) {
reloadStored()
}
override fun onResume() {
super.onResume()
reloadStored()
bookmarksUpdatedEvent += ::bookmarksUpdated
afterPluginsLoadedEvent += ::afterPluginsLoaded
mainPluginsLoadedEvent += ::afterMainPluginsLoaded
}
override fun onStop() {
bookmarksUpdatedEvent -= ::bookmarksUpdated
afterPluginsLoadedEvent -= ::afterPluginsLoaded
mainPluginsLoadedEvent -= ::afterMainPluginsLoaded
super.onStop()

View File

@ -850,6 +850,7 @@ open class ResultFragment : ResultTrailerPlayer() {
}
observe(viewModel.page) { data ->
if(data == null) return@observe
when (data) {
is Resource.Success -> {
val d = data.value

View File

@ -55,7 +55,6 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import kotlinx.coroutines.*
import java.io.File
import java.lang.Math.abs
import java.util.concurrent.TimeUnit
@ -314,6 +313,11 @@ data class ExtractedTrailerData(
class ResultViewModel2 : ViewModel() {
private var currentResponse: LoadResponse? = null
fun clear() {
currentResponse = null
_page.postValue(null)
}
data class EpisodeIndexer(
val dubStatus: DubStatus,
val season: Int,
@ -340,9 +344,9 @@ class ResultViewModel2 : ViewModel() {
//private val currentHeaderName get() = currentResponse?.name
private val _page: MutableLiveData<Resource<ResultData>> =
MutableLiveData(Resource.Loading())
val page: LiveData<Resource<ResultData>> = _page
private val _page: MutableLiveData<Resource<ResultData>?> =
MutableLiveData(null)
val page: LiveData<Resource<ResultData>?> = _page
private val _episodes: MutableLiveData<ResourceSome<List<ResultEpisode>>> =
MutableLiveData(ResourceSome.Loading())
@ -398,7 +402,6 @@ class ResultViewModel2 : ViewModel() {
private val _selectedDubStatusIndex: MutableLiveData<Int> = MutableLiveData(-1)
val selectedDubStatusIndex: LiveData<Int> = _selectedDubStatusIndex
private val _loadedLinks: MutableLiveData<Some<LinkProgress>> = MutableLiveData(Some.None)
val loadedLinks: LiveData<Some<LinkProgress>> = _loadedLinks
@ -1627,10 +1630,11 @@ class ResultViewModel2 : ViewModel() {
if (ranges?.contains(range) != true) {
// if the current ranges does not include the range then select the range with the closest matching start episode
// this usually happends when dub has less episodes then sub -> the range does not exist
ranges?.minByOrNull { kotlin.math.abs(it.startEpisode - range.startEpisode) }?.let { r ->
postEpisodeRange(indexer, r)
return
}
ranges?.minByOrNull { kotlin.math.abs(it.startEpisode - range.startEpisode) }
?.let { r ->
postEpisodeRange(indexer, r)
return
}
}
val isMovie = currentResponse?.isMovie() == true
@ -2111,6 +2115,7 @@ class ResultViewModel2 : ViewModel() {
showFillers: Boolean,
dubStatus: DubStatus,
autostart: AutoResume?,
loadTrailers: Boolean = true,
) =
viewModelScope.launchSafe {
_page.postValue(Resource.Loading(url))
@ -2189,8 +2194,8 @@ class ResultViewModel2 : ViewModel() {
System.currentTimeMillis(),
)
)
loadTrailers(data.value)
if (loadTrailers)
loadTrailers(data.value)
postSuccessful(
data.value,
updateEpisodes = true,

View File

@ -45,6 +45,7 @@ import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.updateChips
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.ownHide
import com.lagradost.cloudstream3.utils.AppUtils.ownShow
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
import com.lagradost.cloudstream3.utils.Coroutines.main
@ -121,6 +122,7 @@ class SearchFragment : Fragment() {
override fun onDestroyView() {
hideKeyboard()
bottomSheetDialog?.ownHide()
super.onDestroyView()
}

View File

@ -3,11 +3,13 @@ package com.lagradost.cloudstream3.ui.search
import android.app.Activity
import android.widget.Toast
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_PLAY_FILE
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
import com.lagradost.cloudstream3.ui.download.DownloadClickEvent
import com.lagradost.cloudstream3.ui.result.START_ACTION_LOAD_EP
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.loadSearchResult
import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
@ -54,7 +56,15 @@ object SearchHelper {
}
}
SEARCH_ACTION_SHOW_METADATA -> {
showToast(activity, callback.card.name, Toast.LENGTH_SHORT)
if(!isTvSettings()) { // we only want this on phone as UI is not done yet on tv
(activity as? MainActivity?)?.apply {
loadPopup(callback.card)
} ?: kotlin.run {
showToast(activity, callback.card.name, Toast.LENGTH_SHORT)
}
} else {
showToast(activity, callback.card.name, Toast.LENGTH_SHORT)
}
}
}
}

View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8"?>
<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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/resultview_preview_result"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="12dp">
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/rounded_image_radius">
<ImageView
android:id="@+id/resultview_preview_poster"
android:layout_width="88dp"
android:layout_height="138dp"
android:contentDescription="@string/poster_image"
android:scaleType="centerCrop"
tools:src="@drawable/example_poster" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="138dp"
android:layout_marginStart="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/resultview_preview_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/textColor"
android:textSize="16sp"
android:textStyle="bold"
tools:text="The Perfect Run">
</TextView>
<com.lagradost.cloudstream3.widget.FlowLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemSpacing="10dp">
<TextView
android:id="@+id/resultview_preview_meta_type"
style="@style/ResultInfoText"
tools:text="Movie" />
<TextView
android:id="@+id/resultview_preview_meta_year"
style="@style/ResultInfoText"
tools:text="2022" />
<TextView
android:id="@+id/resultview_preview_meta_rating"
style="@style/ResultInfoText"
tools:text="Rated: 8.5/10.0" />
<TextView
android:id="@+id/resultview_preview_meta_status"
style="@style/ResultInfoText"
tools:text="Ongoing" />
<TextView
android:id="@+id/resultview_preview_meta_duration"
style="@style/ResultInfoText"
tools:text="121min" />
</com.lagradost.cloudstream3.widget.FlowLayout>
<!-- <TextView
android:id="@+id/resultview_preview_year"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/grayTextColor"
tools:text="2023" />-->
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/resultview_preview_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:textColor="?attr/textColor"
tools:text="Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. " />
<View
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_gravity="bottom"
android:background="@drawable/background_shadow" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/resultview_preview_more_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:padding="12dp"
android:text="@string/home_more_info"
android:textColor="?attr/textColor"
app:drawableRightCompat="@drawable/ic_baseline_arrow_forward_24"
app:drawableTint="?attr/white" />
</LinearLayout>
<FrameLayout
android:id="@+id/resultview_preview_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:visibility="visible">
<com.facebook.shimmer.ShimmerFrameLayout
android:id="@+id/resultview_preview_loading_shimmer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:orientation="vertical"
app:shimmer_auto_start="true"
app:shimmer_base_alpha="0.2"
app:shimmer_duration="@integer/loading_time"
app:shimmer_highlight_alpha="0.3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/result_padding"
android:layout_marginTop="@dimen/result_padding"
android:layout_marginEnd="@dimen/result_padding"
android:orientation="horizontal">
<include layout="@layout/loading_poster" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<include layout="@layout/loading_line" />
<include layout="@layout/loading_line_short" />
<include layout="@layout/loading_line" />
<include layout="@layout/loading_line" />
<include layout="@layout/loading_line" />
</LinearLayout>
</LinearLayout>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="26dp"
android:layout_margin="@dimen/result_padding"
android:layout_marginBottom="@dimen/loading_margin"
android:background="@color/grayShimmer"
app:cardCornerRadius="@dimen/loading_radius"
tools:ignore="ContentDescription" />
</LinearLayout>
</com.facebook.shimmer.ShimmerFrameLayout>
</FrameLayout>
</FrameLayout>

View File

@ -1,59 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:paddingTop="@dimen/loading_margin"
android:paddingBottom="@dimen/loading_margin"
android:layout_height="200dp"
android:layout_width="match_parent">
android:layout_width="match_parent"
android:layout_height="200dp"
android:orientation="vertical"
android:paddingTop="@dimen/loading_margin"
android:paddingBottom="@dimen/loading_margin">
<include layout="@layout/loading_line_short" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<include layout="@layout/loading_poster" />
<View
android:layout_height="wrap_content"
android:layout_width="@dimen/loading_margin" />
android:layout_width="@dimen/loading_margin"
android:layout_height="wrap_content" />
<include layout="@layout/loading_poster" />
<View
android:layout_height="wrap_content"
android:layout_width="@dimen/loading_margin" />
android:layout_width="@dimen/loading_margin"
android:layout_height="wrap_content" />
<include layout="@layout/loading_poster" />
<View
android:layout_height="wrap_content"
android:layout_width="@dimen/loading_margin" />
android:layout_width="@dimen/loading_margin"
android:layout_height="wrap_content" />
<include layout="@layout/loading_poster" />
<View
android:layout_height="wrap_content"
android:layout_width="@dimen/loading_margin" />
android:layout_width="@dimen/loading_margin"
android:layout_height="wrap_content" />
<include layout="@layout/loading_poster" />
<View
android:layout_height="wrap_content"
android:layout_width="@dimen/loading_margin" />
android:layout_width="@dimen/loading_margin"
android:layout_height="wrap_content" />
<include layout="@layout/loading_poster" />
<View
android:layout_height="match_parent"
android:layout_width="@dimen/loading_margin" />
android:layout_width="@dimen/loading_margin"
android:layout_height="match_parent" />
<include layout="@layout/loading_poster" />
<View
android:layout_height="wrap_content"
android:layout_width="@dimen/loading_margin" />
android:layout_width="@dimen/loading_margin"
android:layout_height="wrap_content" />
<include layout="@layout/loading_poster" />
</LinearLayout>