diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt index 30c037bd..68af20dd 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainAPI.kt @@ -47,6 +47,13 @@ object APIHolder { return apis[defProvider] } + fun getApiFromNameNull(apiName: String?): MainAPI? { + for (api in apis) { + if (apiName == api.name) + return api + } + return null + } fun LoadResponse.getId(): Int { return url.replace(getApiFromName(apiName).mainUrl, "").hashCode() @@ -70,14 +77,19 @@ abstract class MainAPI { /**If link is stored in the "data" string, so links can be instantly loaded*/ open val instantLinkLoading = false - open val hasQuickSearch = false - /**Set false if links require referer or for some reason cant be played on a chromecast*/ open val hasChromecastSupport = true /**If all links are m3u8 then set this to false*/ open val hasDownloadSupport = true + open val hasMainPage = false + open val hasQuickSearch = false + + open fun getMainPage() : HomePageResponse? { + return null + } + open fun search(query: String): ArrayList? { return null } @@ -161,6 +173,15 @@ fun TvType.isMovieType(): Boolean { data class SubtitleFile(val lang: String, val url: String) +class HomePageResponse( + val items: List +) + +class HomePageList( + val name: String, + val list: List +) + interface SearchResponse { val name: String val url: String // PUBLIC URL FOR OPEN IN APP diff --git a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt index 09f02427..d4d32ed2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/animeproviders/ShiroProvider.kt @@ -9,6 +9,7 @@ import java.net.URLEncoder import java.util.* import kotlin.collections.ArrayList +const val SHIRO_TIMEOUT_TIME = 60.0 class ShiroProvider : MainAPI() { companion object { @@ -55,6 +56,9 @@ class ShiroProvider : MainAPI() { override val hasQuickSearch: Boolean get() = true + override val hasMainPage: Boolean + get() = true + data class ShiroSearchResponseShow( @JsonProperty("image") val image: String, @JsonProperty("_id") val _id: String, @@ -134,6 +138,46 @@ class ShiroProvider : MainAPI() { @JsonProperty("status") val status: String, ) + data class ShiroHomePageData( + @JsonProperty("trending_animes") val trending_animes: List, + @JsonProperty("ongoing_animes") val ongoing_animes: List, + @JsonProperty("latest_animes") val latest_animes: List, + @JsonProperty("latest_episodes") val latest_episodes: List, + ) + + data class ShiroHomePage( + @JsonProperty("status") val status: String, + @JsonProperty("data") val data: ShiroHomePageData, + @JsonProperty("random") var random: AnimePage?, + ) + + private fun toHomePageList(list: List, name: String): HomePageList { + return HomePageList(name, list.map { data -> + val type = getType(data.type) + val isDubbed = + data.language == "dubbed" + + val set: EnumSet = + EnumSet.of(if (isDubbed) DubStatus.Dubbed else DubStatus.Subbed) + + val episodeCount = data.episodeCount?.toIntOrNull() + + return@map AnimeSearchResponse( + data.name.replace("Dubbed", ""), // i.english ?: i.canonicalTitle, + "$mainUrl/anime/${data.slug}", + data.slug, + this.name, + type, + "https://cdn.shiro.is/${data.image}", + data.year?.toIntOrNull(), + data.canonicalTitle, + set, + if (isDubbed) episodeCount else null, + if (!isDubbed) episodeCount else null, + ) + }.toList()) + } + private fun turnSearchIntoResponse(data: ShiroSearchResponseShow): AnimeSearchResponse { val type = getType(data.type) val isDubbed = @@ -141,12 +185,9 @@ class ShiroProvider : MainAPI() { data.language == "dubbed" else data.slug.contains("dubbed") - val set: EnumSet = EnumSet.noneOf(DubStatus::class.java) + val set: EnumSet = + EnumSet.of(if (isDubbed) DubStatus.Dubbed else DubStatus.Subbed) - if (isDubbed) - set.add(DubStatus.Dubbed) - else - set.add(DubStatus.Subbed) val episodeCount = data.episodeCount?.toIntOrNull() return AnimeSearchResponse( @@ -164,7 +205,26 @@ class ShiroProvider : MainAPI() { ) } - override fun quickSearch(query: String): ArrayList { + override fun getMainPage(): HomePageResponse? { + if (!autoLoadToken()) return null + + val url = "https://tapi.shiro.is/latest?token=$token" + val response = khttp.get(url, timeout = SHIRO_TIMEOUT_TIME) + val res = response.text.let { mapper.readValue(it) } + + val d = res.data + return HomePageResponse( + listOf( + toHomePageList(d.trending_animes, "Trending"), + toHomePageList(d.ongoing_animes, "Ongoing"), + toHomePageList(d.latest_animes, "Latest") + ) + ) + } + + override fun quickSearch(query: String): ArrayList? { + if (!autoLoadToken()) return null + val returnValue: ArrayList = ArrayList() val response = khttp.get( @@ -214,8 +274,8 @@ class ShiroProvider : MainAPI() { val episodes = ArrayList( data.episodes?.distinctBy { it.episode_number }?.sortedBy { it.episode_number } - ?.map { AnimeEpisode(it.videos[0].video_id) } - ?: ArrayList()) + ?.map { AnimeEpisode(it.videos[0].video_id) } + ?: ArrayList()) val status = when (data.status) { "current" -> ShowStatus.Ongoing "finished" -> ShowStatus.Completed diff --git a/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt b/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt index 73c0b296..e4a61e95 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import com.bumptech.glide.load.HttpException +import com.lagradost.cloudstream3.ui.ErrorLoadingException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.net.SocketTimeoutException @@ -67,6 +68,9 @@ suspend fun safeApiCall( is UnknownHostException -> { Resource.Failure(true, null, null, "Cannot connect to server, try again later.") } + is ErrorLoadingException -> { + Resource.Failure(true, null, null, "Error loading, try again later.") + } else -> { val stackTraceMsg = throwable.localizedMessage + "\n\n" + throwable.stackTrace.joinToString( separator = "\n" diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/APIRepository.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/APIRepository.kt new file mode 100644 index 00000000..79b64b0f --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/APIRepository.kt @@ -0,0 +1,47 @@ +package com.lagradost.cloudstream3.ui + +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.mvvm.normalSafeApiCall +import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.utils.ExtractorLink + +class ErrorLoadingException(message: String) : Exception(message) + +class APIRepository(val api: MainAPI) { + val name : String get() = api.name + val mainUrl : String get() = api.mainUrl + + suspend fun load(url: String): Resource { + return safeApiCall { + api.load(url) ?: throw ErrorLoadingException("Error Loading") + } + } + + suspend fun search(query: String): Resource> { + return safeApiCall { + api.search(query) ?: throw ErrorLoadingException("Error Loading") + } + } + + suspend fun quickSearch(query: String): Resource> { + return safeApiCall { + api.quickSearch(query) ?: throw ErrorLoadingException("Error Loading") + } + } + + suspend fun getMainPage(): Resource { + return safeApiCall { + api.getMainPage() ?: throw ErrorLoadingException("Error Loading") + } + } + + fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + return normalSafeApiCall { api.loadLinks(data, isCasting, subtitleCallback, callback) } ?: false + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt new file mode 100644 index 00000000..cedd613c --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt @@ -0,0 +1,105 @@ +package com.lagradost.cloudstream3.ui.home + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.cardview.widget.CardView +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide +import com.bumptech.glide.load.model.GlideUrl +import com.lagradost.cloudstream3.* +import kotlinx.android.synthetic.main.home_result_grid.view.* + +class HomeChildItemAdapter( + var cardList: List, + private val clickCallback: (SearchResponse) -> Unit +) : + RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val layout = R.layout.home_result_grid + return CardViewHolder( + LayoutInflater.from(parent.context).inflate(layout, parent, false), clickCallback + ) + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is CardViewHolder -> { + holder.bind(cardList[position]) + } + } + } + + override fun getItemCount(): Int { + return cardList.size + } + + class CardViewHolder + constructor(itemView: View, private val clickCallback: (SearchResponse) -> Unit) : + RecyclerView.ViewHolder(itemView) { + val cardView: ImageView = itemView.imageView + private val cardText: TextView = itemView.imageText + private val textType: TextView? = itemView.text_type + // val search_result_lang: ImageView? = itemView.search_result_lang + + private val textIsDub: View? = itemView.text_is_dub + private val textIsSub: View? = itemView.text_is_sub + + //val cardTextExtra: TextView? = itemView.imageTextExtra + //val imageTextProvider: TextView? = itemView.imageTextProvider + private val bg: CardView = itemView.backgroundCard + + fun bind(card: Any) { + if (card is SearchResponse) { // GENERIC + + textType?.text = when (card.type) { + TvType.Anime -> "Anime" + TvType.Movie -> "Movie" + TvType.ONA -> "ONA" + TvType.TvSeries -> "TV" + } + // search_result_lang?.visibility = View.GONE + + textIsDub?.visibility = View.GONE + textIsSub?.visibility = View.GONE + + cardText.text = card.name + + //imageTextProvider.text = card.apiName + if (!card.posterUrl.isNullOrEmpty()) { + + val glideUrl = + GlideUrl(card.posterUrl) + + Glide.with(cardView.context) + .load(glideUrl) + .into(cardView) + + } + + bg.setOnClickListener { + clickCallback.invoke(card) + // (activity as AppCompatActivity).loadResult(card.url, card.slug, card.apiName) + } + + when (card) { + is AnimeSearchResponse -> { + if (card.dubStatus?.size == 1) { + //search_result_lang?.visibility = View.VISIBLE + if (card.dubStatus.contains(DubStatus.Dubbed)) { + textIsDub?.visibility = View.VISIBLE + //search_result_lang?.setColorFilter(ContextCompat.getColor(activity, R.color.dubColor)) + } else if (card.dubStatus.contains(DubStatus.Subbed)) { + //search_result_lang?.setColorFilter(ContextCompat.getColor(activity, R.color.subColor)) + textIsSub?.visibility = View.VISIBLE + } + } + } + } + } + } + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt index a97e6da3..9c4e7c34 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt @@ -4,14 +4,20 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.TextView import androidx.fragment.app.Fragment -import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.mvvm.observe +import com.lagradost.cloudstream3.utils.DataStore.getKey +import com.lagradost.cloudstream3.utils.DataStore.setKey +import com.lagradost.cloudstream3.utils.HOMEPAGE_API +import kotlinx.android.synthetic.main.fragment_child_downloads.* +import kotlinx.android.synthetic.main.fragment_home.* class HomeFragment : Fragment() { - private lateinit var homeViewModel: HomeViewModel override fun onCreateView( @@ -21,11 +27,40 @@ class HomeFragment : Fragment() { ): View? { homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java) - val root = inflater.inflate(R.layout.fragment_home, container, false) - val textView: TextView = root.findViewById(R.id.text_home) - homeViewModel.text.observe(viewLifecycleOwner, Observer { - textView.text = it - }) - return root + + return inflater.inflate(R.layout.fragment_home, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + observe(homeViewModel.apiName) { + context?.setKey(HOMEPAGE_API, it) + } + + observe(homeViewModel.page) { + when (it) { + is Resource.Success -> { + val d = it.value + (home_master_recycler?.adapter as ParentItemAdapter?)?.itemList = d.items + home_master_recycler?.adapter?.notifyDataSetChanged() + } + is Resource.Failure -> { + + } + is Resource.Loading -> { + + } + } + } + + val adapter: RecyclerView.Adapter = ParentItemAdapter(listOf()) { + + } + + home_master_recycler.adapter = adapter + home_master_recycler.layoutManager = GridLayoutManager(context, 1) + + homeViewModel.load(context?.getKey(HOMEPAGE_API)) } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt new file mode 100644 index 00000000..2a74df07 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt @@ -0,0 +1,51 @@ +package com.lagradost.cloudstream3.ui.home + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.lagradost.cloudstream3.HomePageList +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.SearchResponse +import kotlinx.android.synthetic.main.fragment_home.* +import kotlinx.android.synthetic.main.homepage_parent.view.* + +class ParentItemAdapter( + var itemList: List, + private val clickCallback: (SearchResponse) -> Unit +) : RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, i: Int): ParentViewHolder { + val layout = R.layout.homepage_parent + return ParentViewHolder( + LayoutInflater.from(parent.context).inflate(layout, parent, false), clickCallback + ) + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + when (holder) { + is ParentViewHolder -> { + holder.bind(itemList[position]) + } + } + } + + override fun getItemCount(): Int { + return itemList.size + } + + class ParentViewHolder + constructor(itemView: View, private val clickCallback: (SearchResponse) -> Unit) : + RecyclerView.ViewHolder(itemView) { + val title: TextView = itemView.home_parent_item_title + val recyclerView: RecyclerView = itemView.home_child_recyclerview + fun bind(info: HomePageList) { + title.text = info.name + recyclerView.adapter = HomeChildItemAdapter(info.list, clickCallback) + recyclerView.layoutManager = GridLayoutManager(itemView.context, 1) + (recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged() + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt index 654e449a..040da1bf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt @@ -3,11 +3,35 @@ package com.lagradost.cloudstream3.ui.home import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.lagradost.cloudstream3.APIHolder.apis +import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.HomePageResponse +import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.ui.APIRepository +import kotlinx.coroutines.launch class HomeViewModel : ViewModel() { + var repo: APIRepository? = null - private val _text = MutableLiveData().apply { - value = "This is home Fragment" + private val _apiName = MutableLiveData() + val apiName: LiveData = _apiName + + private val _page = MutableLiveData>() + val page: LiveData> = _page + + private fun autoloadRepo(): APIRepository { + return APIRepository(apis.first { it.hasMainPage }) + } + + fun load(preferredApiName: String?) = viewModelScope.launch { + val api = getApiFromNameNull(preferredApiName) + repo = if (api?.hasMainPage == true) { + APIRepository(api) + } else { + autoloadRepo() + } + _page.postValue(Resource.Loading()) + _page.postValue(repo?.getMainPage()) } - val text: LiveData = _text } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt index a6071035..82435c4c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt @@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.APIHolder.getId import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState @@ -20,6 +21,8 @@ const val EPISODE_RANGE_SIZE = 50 const val EPISODE_RANGE_OVERLOAD = 60 class ResultViewModel : ViewModel() { + var repo : APIRepository? = null + private val _resultResponse: MutableLiveData> = MutableLiveData() private val _episodes: MutableLiveData> = MutableLiveData() private val _publicEpisodes: MutableLiveData> = MutableLiveData() @@ -137,19 +140,14 @@ class ResultViewModel : ViewModel() { updateEpisodes(context, null, copy, selectedSeason.value) } - // THIS SHOULD AT LEAST CLEAN IT UP, SO APIS CAN SWITCH DOMAIN - private fun getId(url: String, api: MainAPI): Int { - return url.replace(api.mainUrl, "").hashCode() - } - fun load(context: Context, url: String, apiName: String) = viewModelScope.launch { _resultResponse.postValue(Resource.Loading(url)) _apiName.postValue(apiName) val api = getApiFromName(apiName) - val data = safeApiCall { - api.load(url) - } + repo = APIRepository(api) + + val data = repo?.load(url) _resultResponse.postValue(data) @@ -278,7 +276,7 @@ class ResultViewModel : ViewModel() { val links = ArrayList() val subs = ArrayList() return safeApiCall { - getApiFromName(_apiName.value).loadLinks(data, isCasting, { subtitleFile -> + repo?.loadLinks(data, isCasting, { subtitleFile -> if (!subs.any { it.url == subtitleFile.url }) { subs.add(subtitleFile) _allEpisodesSubs.value?.set(id, subs) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt index 31b9c1d5..053d398c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt @@ -7,12 +7,14 @@ import androidx.lifecycle.viewModelScope import com.lagradost.cloudstream3.APIHolder.allApi import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.safeApiCall +import com.lagradost.cloudstream3.ui.APIRepository import kotlinx.coroutines.launch class SearchViewModel : ViewModel() { private val _searchResponse: MutableLiveData>> = MutableLiveData() val searchResponse: LiveData>> get() = _searchResponse var searchCounter = 0 + private val repo = APIRepository(allApi) private fun clearSearch() { _searchResponse.postValue(Resource.Success(ArrayList())) @@ -26,9 +28,8 @@ class SearchViewModel : ViewModel() { } val localSearchCounter = searchCounter _searchResponse.postValue(Resource.Loading()) - val data = safeApiCall { - allApi.search(query) - } + val data = repo.search(query) + if(localSearchCounter != searchCounter) return@launch _searchResponse.postValue(data as Resource>?) } @@ -41,9 +42,7 @@ class SearchViewModel : ViewModel() { } val localSearchCounter = searchCounter _searchResponse.postValue(Resource.Loading()) - val data = safeApiCall { - allApi.quickSearch(query) - } + val data = repo.quickSearch(query) if(localSearchCounter != searchCounter) return@launch _searchResponse.postValue(data as Resource>?) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 2d6a171a..7bcf64ef 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -9,6 +9,7 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule const val DOWNLOAD_HEADER_CACHE = "download_header_cache" const val DOWNLOAD_EPISODE_CACHE = "download_episode_cache" const val VIDEO_PLAYER_BRIGHTNESS = "video_player_alpha" +const val HOMEPAGE_API = "home_api_used" const val PREFERENCES_NAME: String = "rebuild_preference" diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index d91141c5..4436b726 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -7,17 +7,10 @@ android:layout_height="match_parent" tools:context=".ui.home.HomeFragment"> - + android:layout_height="match_parent" + tools:listitem="@layout/homepage_parent" + /> \ No newline at end of file diff --git a/app/src/main/res/layout/home_result_grid.xml b/app/src/main/res/layout/home_result_grid.xml new file mode 100644 index 00000000..d02f4dcd --- /dev/null +++ b/app/src/main/res/layout/home_result_grid.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/homepage_parent.xml b/app/src/main/res/layout/homepage_parent.xml new file mode 100644 index 00000000..a2bb495d --- /dev/null +++ b/app/src/main/res/layout/homepage_parent.xml @@ -0,0 +1,33 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/search_result_grid.xml b/app/src/main/res/layout/search_result_grid.xml index 6334a259..8350ca07 100644 --- a/app/src/main/res/layout/search_result_grid.xml +++ b/app/src/main/res/layout/search_result_grid.xml @@ -9,10 +9,8 @@ android:focusable="true" android:clickable="true" android:id="@+id/search_result_root" - >