History now filters out videos of plugins that are not enabled. History now has a list of filters to filter specific plugins. History now shows an icon of which platform a specific history video is on.

This commit is contained in:
Koen J 2025-05-07 12:49:39 +02:00
commit fc59b841d6
6 changed files with 103 additions and 5 deletions

View file

@ -15,6 +15,8 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.futo.platformplayer.*
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.structures.IAsyncPager
import com.futo.platformplayer.api.media.structures.IPager
import com.futo.platformplayer.constructs.TaskHandler
@ -22,10 +24,14 @@ import com.futo.platformplayer.fragment.mainactivity.topbar.NavigationTopBarFrag
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.models.HistoryVideo
import com.futo.platformplayer.states.StateHistory
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.states.StatePlayer
import com.futo.platformplayer.states.StatePlugins
import com.futo.platformplayer.views.ToggleBar
import com.futo.platformplayer.views.adapters.HistoryListViewHolder
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
import com.futo.platformplayer.views.others.TagsView
import com.futo.platformplayer.views.others.Toggle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@ -68,6 +74,8 @@ class HistoryFragment : MainFragment() {
private var _pager: IPager<HistoryVideo>? = null;
private val _results = arrayListOf<HistoryVideo>();
private var _loading = false;
private val _toggleBar: ToggleBar
private var _togglePluginsDisabled = hashSetOf<String>()
private var _automaticNextPageCounter = 0;
@ -79,6 +87,7 @@ class HistoryFragment : MainFragment() {
_clearSearch = findViewById(R.id.button_clear_search);
_editSearch = findViewById(R.id.edit_search);
_tagsView = findViewById(R.id.tags_text);
_toggleBar = findViewById(R.id.toggle_bar)
_tagsView.setPairs(listOf(
Pair(context.getString(R.string.last_hour), 60L),
Pair(context.getString(R.string.last_24_hours), 24L * 60L),
@ -88,6 +97,22 @@ class HistoryFragment : MainFragment() {
Pair(context.getString(R.string.all_time), -1L)
));
val toggles = StatePlatform.instance.getEnabledClients()
.filter { it is JSClient }
.map { plugin ->
val pluginName = plugin.name.lowercase()
ToggleBar.Toggle(if(Settings.instance.home.showHomeFiltersPluginNames) pluginName else "", plugin.icon, !_togglePluginsDisabled.contains(pluginName), { view, active ->
if (active) {
_togglePluginsDisabled.remove(pluginName)
} else {
_togglePluginsDisabled.add(pluginName)
}
filtersChanged()
}).withTag("plugins")
}.toTypedArray()
_toggleBar.setToggles(*toggles)
_adapter = InsertedViewAdapterWithLoader(context, arrayListOf(), arrayListOf(),
{ _results.size },
{ view, _ ->
@ -162,14 +187,15 @@ class HistoryFragment : MainFragment() {
else
it.nextPage();
return@TaskHandler it.getResults();
return@TaskHandler filterResults(it.getResults());
}).success {
setLoading(false);
val posBefore = _results.size;
_results.addAll(it);
_adapter.notifyItemRangeInserted(_adapter.childToParentPosition(posBefore), it.size);
ensureEnoughContentVisible(it)
val res = filterResults(it)
_results.addAll(res);
_adapter.notifyItemRangeInserted(_adapter.childToParentPosition(posBefore), res.size);
ensureEnoughContentVisible(res)
}.exception<Throwable> {
Logger.w(TAG, "Failed to load next page.", it);
UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_next_page), it, {
@ -178,6 +204,10 @@ class HistoryFragment : MainFragment() {
};
}
private fun filtersChanged() {
updatePager()
}
private fun updatePager() {
val query = _editSearch.text.toString();
if (_editSearch.text.isNotEmpty()) {
@ -246,11 +276,23 @@ class HistoryFragment : MainFragment() {
_adapter.setLoading(loading);
}
private fun filterResults(a: List<HistoryVideo>): List<HistoryVideo> {
//TODO: Not an ideal way to do this, plugin id would be better but it is null for HistoryVideo ?
val enabledPluginNames = StatePlatform.instance.getEnabledClients().map { it.name.lowercase() }.toHashSet()
val disabledPluginNames = _togglePluginsDisabled.toHashSet()
return a.filter {
val pluginName = it.video.id.platform.lowercase()
if (!enabledPluginNames.contains(pluginName))
return@filter false
return@filter !disabledPluginNames.contains(pluginName)
};
}
private fun loadPagerInternal(pager: IPager<HistoryVideo>) {
Logger.i(TAG, "Setting new internal pager on feed");
_results.clear();
val toAdd = pager.getResults();
val toAdd = filterResults(pager.getResults())
_results.addAll(toAdd);
_adapter.notifyDataSetChanged();
ensureEnoughContentVisible(toAdd)

View file

@ -97,6 +97,7 @@ class StatePlatform {
private val _icons : HashMap<String, ImageVariable> = HashMap();
private val _iconsByName : HashMap<String, ImageVariable> = HashMap();
val hasClients: Boolean get() = _availableClients.size > 0;
@ -192,6 +193,7 @@ class StatePlatform {
_availableClients.clear();
_icons.clear();
_iconsByName.clear()
_icons[StateDeveloper.DEV_ID] = ImageVariable(null, R.drawable.ic_security_red);
StatePlugins.instance.updateEmbeddedPlugins(context);
@ -200,6 +202,8 @@ class StatePlatform {
for (plugin in StatePlugins.instance.getPlugins()) {
_icons[plugin.config.id] = StatePlugins.instance.getPluginIconOrNull(plugin.config.id) ?:
ImageVariable(plugin.config.absoluteIconUrl, null);
_iconsByName[plugin.config.name.lowercase()] = StatePlugins.instance.getPluginIconOrNull(plugin.config.id) ?:
ImageVariable(plugin.config.absoluteIconUrl, null);
val client = JSClient(context, plugin);
client.onCaptchaException.subscribe { c, ex ->
@ -299,6 +303,15 @@ class StatePlatform {
return null;
}
fun getPlatformIconByName(name: String?) : ImageVariable? {
if(name == null)
return null;
val nameLower = name.lowercase()
if(_iconsByName.containsKey(nameLower))
return _iconsByName[nameLower];
return null;
}
fun setPlatformOrder(platformOrder: List<String>) {
_platformOrderPersistent.values.clear();
_platformOrderPersistent.values.addAll(platformOrder);

View file

@ -17,6 +17,7 @@ import com.futo.platformplayer.models.HistoryVideo
import com.futo.platformplayer.toHumanNumber
import com.futo.platformplayer.toHumanTime
import com.futo.platformplayer.views.others.ProgressBar
import com.futo.platformplayer.views.platform.PlatformIndicator
class HistoryListViewHolder : ViewHolder {
private val _root: ConstraintLayout;
@ -30,6 +31,7 @@ class HistoryListViewHolder : ViewHolder {
private val _imageRemove: ImageButton;
private val _textHeader: TextView;
private val _timeBar: ProgressBar;
private val _thumbnailPlatform: PlatformIndicator
var video: HistoryVideo? = null
private set;
@ -47,6 +49,7 @@ class HistoryListViewHolder : ViewHolder {
_textVideoDuration = itemView.findViewById(R.id.thumbnail_duration);
_containerDuration = itemView.findViewById(R.id.thumbnail_duration_container);
_containerLive = itemView.findViewById(R.id.thumbnail_live_container);
_thumbnailPlatform = itemView.findViewById(R.id.thumbnail_platform)
_imageRemove = itemView.findViewById(R.id.image_trash);
_textHeader = itemView.findViewById(R.id.text_header);
_timeBar = itemView.findViewById(R.id.time_bar);
@ -72,6 +75,7 @@ class HistoryListViewHolder : ViewHolder {
_textName.text = v.video.name;
_textAuthor.text = v.video.author.name;
_textVideoDuration.text = v.video.duration.toHumanTime(false);
_thumbnailPlatform.setPlatformFromClientName(v.video.id.platform)
if(v.video.isLive) {
_containerDuration.visibility = View.GONE;

View file

@ -22,4 +22,15 @@ class PlatformIndicator : androidx.appcompat.widget.AppCompatImageView {
setImageResource(0);
}
}
fun setPlatformFromClientName(name: String?) {
if(name == null)
setImageResource(0);
else {
val result = StatePlatform.instance.getPlatformIconByName(name);
if (result != null)
result.setImageView(this);
else
setImageResource(0);
}
}
}

View file

@ -94,6 +94,25 @@
android:id="@+id/tags_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text_filters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/filters"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:fontFamily="@font/inter_light"
android:textSize="16dp"
android:textColor="@color/white"
android:paddingStart="5dp"
android:paddingTop="15dp"
android:paddingBottom="8dp" />
<com.futo.platformplayer.views.ToggleBar
android:id="@+id/toggle_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>

View file

@ -117,6 +117,15 @@
app:radiusBottomRight="4dp"
app:radiusTopLeft="0dp"
app:radiusTopRight="0dp" />
<com.futo.platformplayer.views.platform.PlatformIndicator
android:id="@+id/thumbnail_platform"
android:layout_width="20dp"
android:layout_height="20dp"
android:contentDescription="@string/cd_platform_indicator"
android:layout_gravity="bottom|start"
android:layout_marginStart="4dp"
android:layout_marginBottom="4dp" />
</FrameLayout>
<TextView