diff --git a/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt index 33be1561..8de0cde8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt @@ -91,18 +91,18 @@ object UIHelper { return color } - fun AppCompatActivity.loadResult(url: String, slug: String, apiName: String) { + fun AppCompatActivity.loadResult(url: String, slug: String, apiName: String, startAction: Int = 0) { this.runOnUiThread { viewModelStore.clear() this.supportFragmentManager.beginTransaction() .setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.pop_enter, R.anim.pop_exit) - .add(R.id.homeRoot, ResultFragment.newInstance(url, slug, apiName)) + .add(R.id.homeRoot, ResultFragment.newInstance(url, slug, apiName, startAction)) .commit() } } - fun Activity?.loadSearchResult(card : SearchResponse) { - (this as AppCompatActivity?)?.loadResult(card.url, card.slug, card.apiName) + fun Activity?.loadSearchResult(card: SearchResponse, startAction: Int = 0) { + (this as AppCompatActivity?)?.loadResult(card.url, card.slug, card.apiName, startAction) } fun Context.getStatusBarHeight(): Int { 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 18dfd39b..61970ce4 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 @@ -1,7 +1,9 @@ package com.lagradost.cloudstream3.ui.home import android.annotation.SuppressLint +import android.content.Intent import android.content.res.Configuration +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -15,6 +17,7 @@ import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.bumptech.glide.load.model.GlideUrl import com.google.android.material.bottomsheet.BottomSheetDialog +import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.AnimeSearchResponse import com.lagradost.cloudstream3.HomePageResponse import com.lagradost.cloudstream3.R @@ -22,9 +25,11 @@ import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar import com.lagradost.cloudstream3.UIHelper.getGridIsCompact import com.lagradost.cloudstream3.UIHelper.loadSearchResult +import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringRes import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.ui.AutofitRecyclerView +import com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST import com.lagradost.cloudstream3.ui.search.SearchAdapter import com.lagradost.cloudstream3.utils.DataStore.getKey import com.lagradost.cloudstream3.utils.DataStore.setKey @@ -78,7 +83,7 @@ class HomeFragment : Fragment() { activity.loadSearchResult(random) } home_main_play.setOnClickListener { - activity.loadSearchResult(random) + activity.loadSearchResult(random, START_ACTION_RESUME_LATEST) } home_main_info.setOnClickListener { activity.loadSearchResult(random) @@ -124,6 +129,14 @@ class HomeFragment : Fragment() { configEvent.invoke(currentSpan) } + private val apiChangeClickListener = View.OnClickListener { view -> + val validAPIs = apis.filter { api -> api.hasMainPage } + + view.popupMenuNoIconsAndNoStringRes(validAPIs.mapIndexed { index, api -> Pair(index, api.name) }) { + homeViewModel.load(validAPIs[itemId]) + } + } + override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) fixGrid() @@ -157,14 +170,16 @@ class HomeFragment : Fragment() { chooseRandomMainPage(currentMainList[currentMainIndex]) } + home_change_api.setOnClickListener(apiChangeClickListener) + observe(homeViewModel.apiName) { context?.setKey(HOMEPAGE_API, it) } - observe(homeViewModel.page) { - when (it) { + observe(homeViewModel.page) { data -> + when (data) { is Resource.Success -> { - val d = it.value + val d = data.value currentHomePage = d (home_master_recycler?.adapter as ParentItemAdapter?)?.items = d.items home_master_recycler?.adapter?.notifyDataSetChanged() @@ -173,12 +188,39 @@ class HomeFragment : Fragment() { currentMainList.add(response) } currentMainIndex = 0 + + home_loading.visibility = View.GONE + home_loading_error.visibility = View.GONE + home_loaded.visibility = View.VISIBLE } is Resource.Failure -> { + result_error_text.text = data.errorString + home_reload_connectionerror.setOnClickListener(apiChangeClickListener) + + home_reload_connection_open_in_browser.setOnClickListener { view -> + val validAPIs = apis//.filter { api -> api.hasMainPage } + + view.popupMenuNoIconsAndNoStringRes(validAPIs.mapIndexed { index, api -> + Pair( + index, + api.name + ) + }) { + val i = Intent(Intent.ACTION_VIEW) + i.data = Uri.parse(validAPIs[itemId].mainUrl) + startActivity(i) + } + } + + home_loading.visibility = View.GONE + home_loading_error.visibility = View.VISIBLE + home_loaded.visibility = View.GONE } is Resource.Loading -> { - + home_loading.visibility = View.VISIBLE + home_loading_error.visibility = View.GONE + home_loaded.visibility = View.GONE } } } @@ -226,6 +268,6 @@ class HomeFragment : Fragment() { home_master_recycler.adapter = adapter home_master_recycler.layoutManager = GridLayoutManager(context, 1) - homeViewModel.load(context?.getKey(HOMEPAGE_API)) + homeViewModel.load(context?.getKey(HOMEPAGE_API)) } } \ 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 040da1bf..f181304d 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 @@ -7,6 +7,7 @@ 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.MainAPI import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.ui.APIRepository import kotlinx.coroutines.launch @@ -24,8 +25,7 @@ class HomeViewModel : ViewModel() { return APIRepository(apis.first { it.hasMainPage }) } - fun load(preferredApiName: String?) = viewModelScope.launch { - val api = getApiFromNameNull(preferredApiName) + fun load(api : MainAPI?) = viewModelScope.launch { repo = if (api?.hasMainPage == true) { APIRepository(api) } else { @@ -34,4 +34,9 @@ class HomeViewModel : ViewModel() { _page.postValue(Resource.Loading()) _page.postValue(repo?.getMainPage()) } + + fun load(preferredApiName: String?) = viewModelScope.launch { + val api = getApiFromNameNull(preferredApiName) + load(api) + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt index f7536dee..b22614c2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt @@ -142,10 +142,11 @@ class EpisodeAdapter( val name = if (card.name == null) "Episode ${card.episode}" else "${card.episode}. ${card.name}" episodeText.text = name - val watchProgress = card.getWatchProgress() + val displayPos = card.getDisplayPosition() + episodeProgress?.max = (card.duration / 1000).toInt() + episodeProgress?.progress = (displayPos / 1000).toInt() - episodeProgress?.progress = (watchProgress * 50).toInt() - episodeProgress?.visibility = if (watchProgress > 0.0f) View.VISIBLE else View.GONE + episodeProgress?.visibility = if (displayPos > 0L) View.VISIBLE else View.GONE if (card.poster != null) { episodePoster?.visibility = View.VISIBLE diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt index c6644dd6..910fa79c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt @@ -73,6 +73,9 @@ import kotlin.collections.HashMap const val MAX_SYNO_LENGH = 300 +const val START_ACTION_NORMAL = 0 +const val START_ACTION_RESUME_LATEST = 1 + data class ResultEpisode( val name: String?, val poster: String?, @@ -133,18 +136,20 @@ fun Context.buildResultEpisode( ) } +/** 0f-1f */ fun ResultEpisode.getWatchProgress(): Float { - return getDisplayPosition().toFloat() / duration + return (getDisplayPosition() / 1000).toFloat() / (duration / 1000).toFloat() } class ResultFragment : Fragment() { companion object { - fun newInstance(url: String, slug: String, apiName: String) = + fun newInstance(url: String, slug: String, apiName: String, startAction: Int = 0) = ResultFragment().apply { arguments = Bundle().apply { putString("url", url) putString("slug", slug) putString("apiName", apiName) + putInt("startAction", startAction) } } } @@ -156,7 +161,7 @@ class ResultFragment : Fragment() { private var currentHeaderName: String? = null private var currentType: TvType? = null private var currentEpisodes: List? = null - var downloadButton : EasyDownloadButton? = null + var downloadButton: EasyDownloadButton? = null override fun onCreateView( inflater: LayoutInflater, @@ -229,6 +234,8 @@ class ResultFragment : Fragment() { } } + var startAction: Int? = null + @SuppressLint("SetTextI18n") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -252,6 +259,7 @@ class ResultFragment : Fragment() { url = arguments?.getString("url") val slug = arguments?.getString("slug") val apiName = arguments?.getString("apiName") ?: return + startAction = arguments?.getInt("startAction") ?: START_ACTION_NORMAL val api = getApiFromName(apiName) if (media_route_button != null) { @@ -459,6 +467,7 @@ class ResultFragment : Fragment() { val isLoaded = when (episodeClick.action) { ACTION_PLAY_EPISODE_IN_PLAYER -> true + ACTION_CLICK_DEFAULT -> true ACTION_CHROME_CAST_EPISODE -> requireLinks(true) ACTION_CHROME_CAST_MIRROR -> requireLinks(true) else -> requireLinks(false) @@ -673,6 +682,23 @@ class ResultFragment : Fragment() { result_bookmark_button.text = getString(it.stringRes) } + observe(viewModel.episodes) { episodeList -> + when (startAction) { + START_ACTION_RESUME_LATEST -> { + for (ep in episodeList) { + if (ep.getWatchProgress() > 0.90f) { // watched too much + continue + } + handleAction(EpisodeClickEvent(ACTION_PLAY_EPISODE_IN_PLAYER, ep)) + startAction = null + break + } + } + else -> { + } + } + } + observe(viewModel.allEpisodes) { allEpisodes = it } diff --git a/app/src/main/res/drawable/ic_outline_home_24.xml b/app/src/main/res/drawable/ic_outline_home_24.xml new file mode 100644 index 00000000..b6db651d --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_home_24.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index f4fa96f9..2e210c1c 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -1,5 +1,5 @@ - - - + + + + + + + + + + + + android:id="@+id/home_change_api" + android:layout_margin="10dp" + android:layout_gravity="end" + android:background="?android:attr/selectableItemBackgroundBorderless" + + android:src="@drawable/ic_outline_settings_24" + android:layout_width="25dp" + android:layout_height="25dp" + android:contentDescription="@string/home_change_provider"> - + android:layout_width="150dp" + android:layout_height="212dp" + android:contentDescription="@string/home_main_poster"> - - - + + + + - - - + app:rippleColor="?attr/grayBackground" + android:textColor="?attr/grayBackground" + app:iconTint="?attr/grayBackground" + android:textAllCaps="false" + android:clickable="true" + android:focusable="true" + app:iconGravity="textStart" + app:strokeColor="?attr/grayBackground" + app:backgroundTint="?attr/textColor" + app:icon="@drawable/ic_baseline_play_arrow_24" + android:layout_width="120dp" + android:layout_height="50dp"> + + + + + + + - - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_result.xml b/app/src/main/res/layout/fragment_result.xml index a6ba4671..59a43d15 100644 --- a/app/src/main/res/layout/fragment_result.xml +++ b/app/src/main/res/layout/fragment_result.xml @@ -18,6 +18,7 @@ android:layout_width="50dp" android:layout_height="50dp"> @@ -48,17 +54,21 @@ android:layout_height="50dp" android:layout_margin="5dp" + app:iconGravity="textStart" + app:strokeColor="?attr/textColor" + android:backgroundTint="?attr/grayBackground" + app:rippleColor="?attr/textColor" + android:textColor="?attr/textColor" + app:iconTint="?attr/textColor" + android:textAllCaps="false" + android:textStyle="bold" + app:icon="@drawable/ic_baseline_public_24" app:iconSize="20dp" android:text="@string/result_open_in_browser" android:id="@+id/result_reload_connection_open_in_browser" - android:textAllCaps="false" android:textSize="15sp" app:cornerRadius="5dp" - app:strokeWidth="2dp" - app:strokeColor="@color/colorAccent" - style="@style/Widget.MaterialComponents.Button.OutlinedButton" - app:rippleColor="@color/colorPrimary" android:layout_width="wrap_content" android:minWidth="200dp" > @@ -68,7 +78,7 @@ android:gravity="center" android:layout_gravity="center" android:id="@+id/result_error_text" - android:textColor="?attr/colorPrimary" + android:textColor="?attr/textColor" android:layout_width="match_parent" android:layout_height="wrap_content"> diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml index ab5759e1..e3fd3d22 100644 --- a/app/src/main/res/menu/bottom_nav_menu.xml +++ b/app/src/main/res/menu/bottom_nav_menu.xml @@ -3,7 +3,7 @@ Play Info Next Random + Change Provider \ No newline at end of file