diff --git a/.gitmodules b/.gitmodules index 3ba3f3f6..00037939 100644 --- a/.gitmodules +++ b/.gitmodules @@ -100,3 +100,9 @@ [submodule "app/src/unstable/assets/sources/curiositystream"] path = app/src/unstable/assets/sources/curiositystream url = ../plugins/curiositystream.git +[submodule "app/src/unstable/assets/sources/crunchyroll"] + path = app/src/unstable/assets/sources/crunchyroll + url = ../plugins/crunchyroll.git +[submodule "app/src/stable/assets/sources/crunchyroll"] + path = app/src/stable/assets/sources/crunchyroll + url = ../plugins/crunchyroll.git diff --git a/app/build.gradle b/app/build.gradle index 88cd4558..fcbd422c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -198,6 +198,7 @@ dependencies { implementation 'com.google.android.flexbox:flexbox:3.0.0' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation fileTree(dir: 'aar', include: ['*.aar']) + implementation 'com.arthenica:smart-exception-java:0.2.1' implementation 'org.jetbrains.kotlin:kotlin-reflect:1.9.0' implementation 'com.github.dhaval2404:imagepicker:2.1' implementation 'com.google.zxing:core:3.4.1' diff --git a/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt b/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt index 109d0941..7b236355 100644 --- a/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt +++ b/app/src/main/java/com/futo/platformplayer/UISlideOverlays.kt @@ -1123,8 +1123,8 @@ class UISlideOverlays { return SlideUpMenuOverlay(container.context, container, container.context.getString(R.string.add_to), null, true, items).apply { show() }; } - fun showFiltersOverlay(lifecycleScope: CoroutineScope, container: ViewGroup, enabledClientsIds: List, filterValues: HashMap>, isChannelSearch: Boolean = false): SlideUpMenuFilters { - val overlay = SlideUpMenuFilters(lifecycleScope, container, enabledClientsIds, filterValues, isChannelSearch); + fun showFiltersOverlay(lifecycleScope: CoroutineScope, container: ViewGroup, enabledClientsIds: List, filterValues: HashMap>): SlideUpMenuFilters { + val overlay = SlideUpMenuFilters(lifecycleScope, container, enabledClientsIds, filterValues); overlay.show(); return overlay; } diff --git a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt index 788fd4c1..14be4fdf 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/channel/tab/ChannelContentsFragment.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.FrameLayout import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -25,6 +26,7 @@ import com.futo.platformplayer.api.media.structures.MultiPager import com.futo.platformplayer.constructs.Event1 import com.futo.platformplayer.constructs.Event2 import com.futo.platformplayer.constructs.TaskHandler +import com.futo.platformplayer.dp import com.futo.platformplayer.engine.exceptions.PluginException import com.futo.platformplayer.engine.exceptions.ScriptCaptchaRequiredException import com.futo.platformplayer.exceptions.ChannelException @@ -32,9 +34,11 @@ import com.futo.platformplayer.fragment.mainactivity.main.FeedView import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.states.StateCache import com.futo.platformplayer.states.StatePlatform +import com.futo.platformplayer.states.StatePlugins import com.futo.platformplayer.states.StatePolycentric import com.futo.platformplayer.states.StateSubscriptions import com.futo.platformplayer.views.FeedStyle +import com.futo.platformplayer.views.SearchView import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader import com.futo.platformplayer.views.adapters.feedtypes.PreviewContentListAdapter @@ -54,6 +58,8 @@ class ChannelContentsFragment(private val subType: String? = null) : Fragment(), private var _results: ArrayList = arrayListOf(); private var _adapterResults: InsertedViewAdapterWithLoader? = null; private var _lastPolycentricProfile: PolycentricProfile? = null; + private var _query: String? = null + private var _searchView: SearchView? = null val onContentClicked = Event2(); val onContentUrlClicked = Event2(); @@ -68,17 +74,32 @@ class ChannelContentsFragment(private val subType: String? = null) : Fragment(), private fun getContentPager(channel: IPlatformChannel): IPager { Logger.i(TAG, "getContentPager"); - val lastPolycentricProfile = _lastPolycentricProfile; - var pager: IPager? = null; - if (lastPolycentricProfile != null && StatePolycentric.instance.enabled) - pager = - StatePolycentric.instance.getChannelContent(lifecycleScope, lastPolycentricProfile, type = subType); + var pager: IPager? = null + val query = _query + if (!query.isNullOrBlank()) { + if(subType != null) { + Logger.i(TAG, "StatePlatform.instance.searchChannel(channel.url = ${channel.url}, query = ${query}, subType = ${subType})") + pager = StatePlatform.instance.searchChannel(channel.url, query, subType); + } else { + Logger.i(TAG, "StatePlatform.instance.searchChannel(channel.url = ${channel.url}, query = ${query})") + pager = StatePlatform.instance.searchChannel(channel.url, query); + } + } else { + val lastPolycentricProfile = _lastPolycentricProfile; + if (lastPolycentricProfile != null && StatePolycentric.instance.enabled) { + pager = StatePolycentric.instance.getChannelContent(lifecycleScope, lastPolycentricProfile, type = subType); + Logger.i(TAG, "StatePolycentric.instance.getChannelContent(lifecycleScope, lastPolycentricProfile, type = ${subType})") + } - if(pager == null) { - if(subType != null) - pager = StatePlatform.instance.getChannelContent(channel.url, subType); - else - pager = StatePlatform.instance.getChannelContent(channel.url); + if(pager == null) { + if(subType != null) { + pager = StatePlatform.instance.getChannelContent(channel.url, subType); + Logger.i(TAG, "StatePlatform.instance.getChannelContent(channel.url = ${channel.url}, subType = ${subType})") + } else { + pager = StatePlatform.instance.getChannelContent(channel.url); + Logger.i(TAG, "StatePlatform.instance.getChannelContent(channel.url = ${channel.url})") + } + } } return pager; } @@ -145,19 +166,44 @@ class ChannelContentsFragment(private val subType: String? = null) : Fragment(), _taskLoadVideos.cancel(); + _query = null _channel = channel; + updateSearchViewVisibility() _results.clear(); _adapterResults?.notifyDataSetChanged(); loadInitial(); } + private fun updateSearchViewVisibility() { + val client = _channel?.id?.pluginId?.let { StatePlatform.instance.getClientOrNull(it) } + Logger.i(TAG, "_searchView.visible = ${client?.capabilities?.hasSearchChannelContents == true}") + _searchView?.visibility = if (client?.capabilities?.hasSearchChannelContents == true) View.VISIBLE else View.GONE + } + + fun setQuery(query: String) { + _query = query + _taskLoadVideos.cancel() + _results.clear() + _adapterResults?.notifyDataSetChanged() + loadInitial() + } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { val view = inflater.inflate(R.layout.fragment_channel_videos, container, false); + _query = null _recyclerResults = view.findViewById(R.id.recycler_videos); - _adapterResults = PreviewContentListAdapter(view.context, FeedStyle.THUMBNAIL, _results, null, Settings.instance.channel.progressBar).apply { + val searchView = SearchView(requireContext()).apply { layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT) }.apply { + onEnter.subscribe { + setQuery(it) + } + } + _searchView = searchView + updateSearchViewVisibility() + + _adapterResults = PreviewContentListAdapter(view.context, FeedStyle.THUMBNAIL, _results, null, Settings.instance.channel.progressBar, viewsToPrepend = arrayListOf(searchView)).apply { this.onContentUrlClicked.subscribe(this@ChannelContentsFragment.onContentUrlClicked::emit); this.onUrlClicked.subscribe(this@ChannelContentsFragment.onUrlClicked::emit); this.onContentClicked.subscribe(this@ChannelContentsFragment.onContentClicked::emit); @@ -174,6 +220,7 @@ class ChannelContentsFragment(private val subType: String? = null) : Fragment(), _recyclerResults?.layoutManager = _glmVideo; _recyclerResults?.addOnScrollListener(_scrollListener); + return view; } @@ -182,6 +229,8 @@ class ChannelContentsFragment(private val subType: String? = null) : Fragment(), _recyclerResults?.removeOnScrollListener(_scrollListener); _recyclerResults = null; _pager = null; + _query = null + _searchView = null _taskLoadVideos.cancel(); _nextPageHandler.cancel(); @@ -304,6 +353,7 @@ class ChannelContentsFragment(private val subType: String? = null) : Fragment(), } private fun loadInitial() { + Logger.i(TAG, "loadInitial") val channel: IPlatformChannel = _channel ?: return; setLoading(true); _taskLoadVideos.run(channel); diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt index 3ac71315..63b60c1f 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ChannelFragment.kt @@ -425,17 +425,15 @@ class ChannelFragment : MainFragment() { _fragment.lifecycleScope.launch(Dispatchers.IO) { val plugin = StatePlatform.instance.getChannelClientOrNull(channel.url) withContext(Dispatchers.Main) { - if (plugin != null && plugin.capabilities.hasSearchChannelContents) { - buttons.add(Pair(R.drawable.ic_search) { - _fragment.navigate( - SuggestionsFragmentData( - "", SearchType.VIDEO, channel.url - ) + buttons.add(Pair(R.drawable.ic_search) { + _fragment.navigate( + SuggestionsFragmentData( + "", SearchType.VIDEO ) - }) + ) + }) + _fragment.topBar?.assume()?.setMenuItems(buttons) - _fragment.topBar?.assume()?.setMenuItems(buttons) - } if(plugin != null && plugin.capabilities.hasGetChannelCapabilities) { if(plugin.getChannelCapabilities()?.types?.contains(ResultCapabilities.TYPE_SHORTS) ?: false && !(_viewPager.adapter as ChannelViewPagerAdapter).containsItem(ChannelTab.SHORTS.ordinal.toLong())) { diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt index 4d517b99..72094903 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/ContentSearchResultsFragment.kt @@ -89,7 +89,6 @@ class ContentSearchResultsFragment : MainFragment() { private var _sortBy: String? = null; private var _filterValues: HashMap> = hashMapOf(); private var _enabledClientIds: List? = null; - private var _channelUrl: String? = null; private var _searchType: SearchType? = null; private val _taskSearch: TaskHandler>; @@ -98,17 +97,12 @@ class ContentSearchResultsFragment : MainFragment() { constructor(fragment: ContentSearchResultsFragment, inflater: LayoutInflater) : super(fragment, inflater) { _taskSearch = TaskHandler>({fragment.lifecycleScope}, { query -> Logger.i(TAG, "Searching for: $query") - val channelUrl = _channelUrl; - if (channelUrl != null) { - StatePlatform.instance.searchChannel(channelUrl, query, null, _sortBy, _filterValues, _enabledClientIds) - } else { - when (_searchType) - { - SearchType.VIDEO -> StatePlatform.instance.searchRefresh(fragment.lifecycleScope, query, null, _sortBy, _filterValues, _enabledClientIds) - SearchType.CREATOR -> StatePlatform.instance.searchChannelsAsContent(query) - SearchType.PLAYLIST -> StatePlatform.instance.searchPlaylist(query) - else -> throw Exception("Search type must be specified") - } + when (_searchType) + { + SearchType.VIDEO -> StatePlatform.instance.searchRefresh(fragment.lifecycleScope, query, null, _sortBy, _filterValues, _enabledClientIds) + SearchType.CREATOR -> StatePlatform.instance.searchChannelsAsContent(query) + SearchType.PLAYLIST -> StatePlatform.instance.searchPlaylist(query) + else -> throw Exception("Search type must be specified") } }) .success { loadedResult(it); }.exception { } @@ -147,7 +141,6 @@ class ContentSearchResultsFragment : MainFragment() { fun onShown(parameter: Any?) { if(parameter is SuggestionsFragmentData) { setQuery(parameter.query, false); - setChannelUrl(parameter.channelUrl, false); setSearchType(parameter.searchType, false) fragment.topBar?.apply { @@ -164,7 +157,7 @@ class ContentSearchResultsFragment : MainFragment() { onFilterClick.subscribe(this) { _overlayContainer.let { val filterValuesCopy = HashMap(_filterValues); - val filtersOverlay = UISlideOverlays.showFiltersOverlay(lifecycleScope, it, _enabledClientIds!!, filterValuesCopy, _channelUrl != null); + val filtersOverlay = UISlideOverlays.showFiltersOverlay(lifecycleScope, it, _enabledClientIds!!, filterValuesCopy); filtersOverlay.onOK.subscribe { enabledClientIds, changed -> if (changed) { setFilterValues(filtersOverlay.commonCapabilities, filterValuesCopy); @@ -211,11 +204,7 @@ class ContentSearchResultsFragment : MainFragment() { fragment.lifecycleScope.launch(Dispatchers.IO) { try { - val commonCapabilities = - if(_channelUrl == null) - StatePlatform.instance.getCommonSearchCapabilities(StatePlatform.instance.getEnabledClients().map { it.id }); - else - StatePlatform.instance.getCommonSearchChannelContentsCapabilities(StatePlatform.instance.getEnabledClients().map { it.id }); + val commonCapabilities = StatePlatform.instance.getCommonSearchCapabilities(StatePlatform.instance.getEnabledClients().map { it.id }); val sorts = commonCapabilities?.sorts ?: listOf(); if (sorts.size > 1) { withContext(Dispatchers.Main) { @@ -282,15 +271,6 @@ class ContentSearchResultsFragment : MainFragment() { } } - private fun setChannelUrl(channelUrl: String?, updateResults: Boolean = true) { - _channelUrl = channelUrl; - - if (updateResults) { - clearResults(); - loadResults(); - } - } - private fun setSearchType(searchType: SearchType, updateResults: Boolean = true) { _searchType = searchType diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt index 58caabe1..5510ccbf 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/PlaylistsFragment.kt @@ -217,7 +217,7 @@ class PlaylistsFragment : MainFragment() { var playlistsToReturn = pls; if(!_listPlaylistsSearch.text.isNullOrEmpty()) playlistsToReturn = playlistsToReturn.filter { it.name.contains(_listPlaylistsSearch.text, true) }; - if(!_ordering.value.isNullOrEmpty()){ + if(!_ordering.value.isNullOrEmpty()) { playlistsToReturn = when(_ordering.value){ "nameAsc" -> playlistsToReturn.sortedBy { it.name.lowercase() } "nameDesc" -> playlistsToReturn.sortedByDescending { it.name.lowercase() }; diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SuggestionsFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SuggestionsFragment.kt index 0dfb867d..e0a68cc5 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SuggestionsFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SuggestionsFragment.kt @@ -21,7 +21,7 @@ import com.futo.platformplayer.views.adapters.SearchSuggestionAdapter import com.futo.platformplayer.views.others.RadioGroupView import com.futo.platformplayer.views.others.TagsView -data class SuggestionsFragmentData(val query: String, val searchType: SearchType, val channelUrl: String? = null); +data class SuggestionsFragmentData(val query: String, val searchType: SearchType); class SuggestionsFragment : MainFragment { override val isMainView : Boolean = true; @@ -34,7 +34,6 @@ class SuggestionsFragment : MainFragment { private val _suggestions: ArrayList = ArrayList(); private var _query: String? = null; private var _searchType: SearchType = SearchType.VIDEO; - private var _channelUrl: String? = null; private val _adapterSuggestions = SearchSuggestionAdapter(_suggestions); @@ -52,7 +51,7 @@ class SuggestionsFragment : MainFragment { _adapterSuggestions.onClicked.subscribe { suggestion -> val storage = FragmentedStorage.get(); storage.add(suggestion); - navigate(SuggestionsFragmentData(suggestion, _searchType, _channelUrl)); + navigate(SuggestionsFragmentData(suggestion, _searchType)); } _adapterSuggestions.onRemove.subscribe { suggestion -> val index = _suggestions.indexOf(suggestion); @@ -109,10 +108,8 @@ class SuggestionsFragment : MainFragment { if (parameter is SuggestionsFragmentData) { _searchType = parameter.searchType; - _channelUrl = parameter.channelUrl; } else if (parameter is SearchType) { _searchType = parameter; - _channelUrl = null; } _radioGroupView?.setOptions(listOf(Pair("Media", SearchType.VIDEO), Pair("Creators", SearchType.CREATOR), Pair("Playlists", SearchType.PLAYLIST)), listOf(_searchType), false, true) @@ -135,7 +132,7 @@ class SuggestionsFragment : MainFragment { } } else - navigate(SuggestionsFragmentData(it, _searchType, _channelUrl)); + navigate(SuggestionsFragmentData(it, _searchType)); }; onTextChange.subscribe(this) { diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt index d1a3e41e..fd2cb19b 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt @@ -2680,9 +2680,10 @@ class VideoDetailView : ConstraintLayout { } onChannelClicked.subscribe { - if(it.url.isNotBlank()) + if(it.url.isNotBlank()) { + fragment.minimizeVideoDetail() fragment.navigate(it) - else + } else UIDialogs.appToast("No author url present"); } diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/SearchTopBarFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/SearchTopBarFragment.kt index 44d8a9ad..15952d0a 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/SearchTopBarFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/topbar/SearchTopBarFragment.kt @@ -88,7 +88,6 @@ class SearchTopBarFragment : TopFragment() { } else if (parameter is SuggestionsFragmentData) { this.setText(parameter.query); _searchType = parameter.searchType; - _channelUrl = parameter.channelUrl; } if(currentMain is SuggestionsFragment) @@ -114,7 +113,7 @@ class SearchTopBarFragment : TopFragment() { fun clear() { _editSearch?.text?.clear(); if (currentMain !is SuggestionsFragment) { - navigate(SuggestionsFragmentData("", _searchType, _channelUrl), false); + navigate(SuggestionsFragmentData("", _searchType), false); } else { onSearch.emit(""); } diff --git a/app/src/main/java/com/futo/platformplayer/views/SearchView.kt b/app/src/main/java/com/futo/platformplayer/views/SearchView.kt index c36a04a5..c7d68127 100644 --- a/app/src/main/java/com/futo/platformplayer/views/SearchView.kt +++ b/app/src/main/java/com/futo/platformplayer/views/SearchView.kt @@ -3,6 +3,8 @@ package com.futo.platformplayer.views import android.content.Context import android.text.TextWatcher import android.util.AttributeSet +import android.view.View +import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputMethodManager import android.widget.FrameLayout import android.widget.ImageButton @@ -30,9 +32,26 @@ class SearchView : FrameLayout { textSearch = findViewById(R.id.edit_search) buttonClear = findViewById(R.id.button_clear_search) - buttonClear.setOnClickListener { textSearch.text = "" }; + buttonClear.setOnClickListener { + textSearch.text = "" + textSearch?.clearFocus() + (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(textSearch.windowToken, 0) + onSearchChanged.emit("") + onEnter.emit("") + } + textSearch.setOnEditorActionListener { _, i, _ -> + if (i == EditorInfo.IME_ACTION_DONE) { + textSearch?.clearFocus() + (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow(textSearch.windowToken, 0) + onEnter.emit(textSearch.text.toString()) + return@setOnEditorActionListener true + } + return@setOnEditorActionListener false + + } textSearch.addTextChangedListener { - onSearchChanged.emit(it.toString()); + buttonClear.visibility = if ((it?.length ?: 0) > 0) View.VISIBLE else View.GONE + onSearchChanged.emit(it.toString()) }; } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuFilters.kt b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuFilters.kt index 75b50a26..9180a3f1 100644 --- a/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuFilters.kt +++ b/app/src/main/java/com/futo/platformplayer/views/overlays/slideup/SlideUpMenuFilters.kt @@ -28,17 +28,14 @@ class SlideUpMenuFilters { private var _changed: Boolean = false; private val _lifecycleScope: CoroutineScope; - private var _isChannelSearch = false; - var commonCapabilities: ResultCapabilities? = null; - constructor(lifecycleScope: CoroutineScope, container: ViewGroup, enabledClientsIds: List, filterValues: HashMap>, isChannelSearch: Boolean = false) { + constructor(lifecycleScope: CoroutineScope, container: ViewGroup, enabledClientsIds: List, filterValues: HashMap>) { _lifecycleScope = lifecycleScope; _container = container; _enabledClientsIds = enabledClientsIds; _filterValues = filterValues; - _isChannelSearch = isChannelSearch; _slideUpMenuOverlay = SlideUpMenuOverlay(_container.context, _container, container.context.getString(R.string.filters), container.context.getString(R.string.done), true, listOf()); _slideUpMenuOverlay.onOK.subscribe { onOK.emit(_enabledClientsIds, _changed); @@ -51,10 +48,7 @@ class SlideUpMenuFilters { private fun updateCommonCapabilities() { _lifecycleScope.launch(Dispatchers.IO) { try { - val caps = if(!_isChannelSearch) - StatePlatform.instance.getCommonSearchCapabilities(_enabledClientsIds); - else - StatePlatform.instance.getCommonSearchChannelContentsCapabilities(_enabledClientsIds); + val caps = StatePlatform.instance.getCommonSearchCapabilities(_enabledClientsIds); synchronized(_filterValues) { if (caps != null) { val keysToRemove = arrayListOf(); diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt index 1daa7808..e209f937 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayer.kt @@ -531,6 +531,8 @@ class FutoVideoPlayer : FutoVideoPlayerBase { fun setLoopVisible(visible: Boolean) { _control_loop.visibility = if (visible) View.VISIBLE else View.GONE; _control_loop_fullscreen.visibility = if (visible) View.VISIBLE else View.GONE; + if (StatePlayer.instance.loopVideo && !visible) + StatePlayer.instance.loopVideo = false } fun stopAllGestures() { diff --git a/app/src/main/res/drawable/ic_launcher_monochrome.xml b/app/src/main/res/drawable/ic_launcher_monochrome.xml new file mode 100644 index 00000000..405bd330 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -0,0 +1,16 @@ + + + + diff --git a/app/src/main/res/layout/activity_sync_pair.xml b/app/src/main/res/layout/activity_sync_pair.xml index e5355ecc..2e5e5651 100644 --- a/app/src/main/res/layout/activity_sync_pair.xml +++ b/app/src/main/res/layout/activity_sync_pair.xml @@ -233,7 +233,7 @@ android:isScrollContainer="true" android:scrollbars="vertical" android:maxHeight="200dp" - android:text="An error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurredAn error has occurred" /> + android:text="An error has occurred" /> \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 036d09bc..081998b2 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 036d09bc..081998b2 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/app/src/stable/assets/sources/crunchyroll b/app/src/stable/assets/sources/crunchyroll new file mode 160000 index 00000000..1aa91f21 --- /dev/null +++ b/app/src/stable/assets/sources/crunchyroll @@ -0,0 +1 @@ +Subproject commit 1aa91f216c0a87604aed1669b63b7830e4288630 diff --git a/app/src/stable/res/raw/plugin_config.json b/app/src/stable/res/raw/plugin_config.json index 4dea0f2e..ce535388 100644 --- a/app/src/stable/res/raw/plugin_config.json +++ b/app/src/stable/res/raw/plugin_config.json @@ -15,7 +15,8 @@ "e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json", "89ae4889-0420-4d16-ad6c-19c776b28f99": "sources/apple-podcasts/ApplePodcastsConfig.json", "8d029a7f-5507-4e36-8bd8-c19a3b77d383": "sources/tedtalks/TedTalksConfig.json", - "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json" + "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json", + "9bb33039-8580-48d4-9849-21319ae845a4": "sources/crunchyroll/CrunchyrollConfig.json" }, "SOURCES_EMBEDDED_DEFAULT": [ "35ae969a-a7db-11ed-afa1-0242ac120002" diff --git a/app/src/unstable/assets/sources/crunchyroll b/app/src/unstable/assets/sources/crunchyroll new file mode 160000 index 00000000..1aa91f21 --- /dev/null +++ b/app/src/unstable/assets/sources/crunchyroll @@ -0,0 +1 @@ +Subproject commit 1aa91f216c0a87604aed1669b63b7830e4288630 diff --git a/app/src/unstable/res/raw/plugin_config.json b/app/src/unstable/res/raw/plugin_config.json index 40b10e11..5abe547e 100644 --- a/app/src/unstable/res/raw/plugin_config.json +++ b/app/src/unstable/res/raw/plugin_config.json @@ -15,7 +15,8 @@ "e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json", "89ae4889-0420-4d16-ad6c-19c776b28f99": "sources/apple-podcasts/ApplePodcastsConfig.json", "8d029a7f-5507-4e36-8bd8-c19a3b77d383": "sources/tedtalks/TedTalksConfig.json", - "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json" + "273b6523-5438-44e2-9f5d-78e0325a8fd9": "sources/curiositystream/CuriosityStreamConfig.json", + "9bb33039-8580-48d4-9849-21319ae845a4": "sources/crunchyroll/CrunchyrollConfig.json" }, "SOURCES_EMBEDDED_DEFAULT": [ "35ae969a-a7db-11ed-afa1-0242ac120002"