From 98d92d3fe294f44ceafeff48b030c9dd0a8cf55c Mon Sep 17 00:00:00 2001
From: Koen <koen@pop-os.localdomain>
Date: Wed, 6 Dec 2023 16:32:17 +0100
Subject: [PATCH] Updated HistoryView to use pager.

---
 .../channel/tab/ChannelContentsFragment.kt    |   4 -
 .../fragment/mainactivity/main/FeedView.kt    |   4 -
 .../mainactivity/main/HistoryFragment.kt      | 310 ++++++++++++++----
 .../views/adapters/HistoryListAdapter.kt      | 119 -------
 .../views/adapters/HistoryListViewHolder.kt   |  30 +-
 5 files changed, 267 insertions(+), 200 deletions(-)
 delete mode 100644 app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListAdapter.kt

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 c1b0127e..0bf75149 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
@@ -101,10 +101,6 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
         return@TaskHandler it.getResults();
     }).success {
         setLoading(false);
-        if (it.isEmpty()) {
-            return@success;
-        }
-
         val posBefore = _results.size;
         val toAdd = it.filter { it is IPlatformVideo }.map { it as IPlatformVideo }
         _results.addAll(toAdd);
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt
index 595f880f..f5294ff7 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt
@@ -132,10 +132,6 @@ abstract class FeedView<TFragment, TResult, TConverted, TPager, TViewHolder> : L
         }).success {
             setLoading(false);
 
-            if (it.isEmpty()) {
-                return@success;
-            }
-
             val posBefore = recyclerData.results.size;
             val filteredResults = filterResults(it);
             recyclerData.results.addAll(filteredResults);
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt
index 8e65eb1e..4cd2d885 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/HistoryFragment.kt
@@ -1,5 +1,6 @@
 package com.futo.platformplayer.fragment.mainactivity.main
 
+import android.annotation.SuppressLint
 import android.content.Context
 import android.os.Bundle
 import android.view.LayoutInflater
@@ -8,88 +9,279 @@ import android.view.ViewGroup
 import android.view.inputmethod.InputMethodManager
 import android.widget.EditText
 import android.widget.ImageButton
+import android.widget.LinearLayout
 import androidx.core.widget.addTextChangedListener
+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.contents.IPlatformContent
+import com.futo.platformplayer.api.media.structures.IAsyncPager
+import com.futo.platformplayer.api.media.structures.IPager
+import com.futo.platformplayer.constructs.TaskHandler
+import com.futo.platformplayer.logging.Logger
+import com.futo.platformplayer.models.HistoryVideo
 import com.futo.platformplayer.states.StateHistory
 import com.futo.platformplayer.states.StatePlayer
-import com.futo.platformplayer.states.StatePlaylists
 import com.futo.platformplayer.views.others.TagsView
-import com.futo.platformplayer.views.adapters.HistoryListAdapter
+import com.futo.platformplayer.views.adapters.HistoryListViewHolder
+import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
 
 class HistoryFragment : MainFragment() {
     override val isMainView : Boolean = true;
     override val isTab: Boolean = true;
     override val hasBottomBar: Boolean get() = true;
 
-    private var _adapter: HistoryListAdapter? = null;
+    private var _view: HistoryView? = null;
 
     override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
-        val view = inflater.inflate(R.layout.fragment_history, container, false);
-
-        val inputMethodManager = view.context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
-
-        val recyclerHistory = view.findViewById<RecyclerView>(R.id.recycler_history);
-        val clearSearch = view.findViewById<ImageButton>(R.id.button_clear_search);
-        val editSearch = view.findViewById<EditText>(R.id.edit_search);
-        var tagsView = view.findViewById<TagsView>(R.id.tags_text);
-        tagsView.setPairs(listOf(
-            Pair(getString(R.string.last_hour), 60L),
-            Pair(getString(R.string.last_24_hours), 24L * 60L),
-            Pair(getString(R.string.last_week), 7L * 24L * 60L),
-            Pair(getString(R.string.last_30_days), 30L * 24L * 60L),
-            Pair(getString(R.string.last_year), 365L * 30L * 24L * 60L),
-            Pair(getString(R.string.all_time), -1L)));
-
-        val adapter = HistoryListAdapter();
-        adapter.onClick.subscribe { v ->
-            val diff = v.video.duration - v.position;
-            val vid: Any = if (diff > 5) { v.video.withTimestamp(v.position) } else { v.video };
-            StatePlayer.instance.clearQueue();
-            navigate<VideoDetailFragment>(vid).maximizeVideoDetail();
-            editSearch.clearFocus();
-            inputMethodManager.hideSoftInputFromWindow(editSearch.windowToken, 0);
-        };
-        _adapter = adapter;
-
-        recyclerHistory.adapter = adapter;
-        recyclerHistory.isSaveEnabled = false;
-        recyclerHistory.layoutManager = LinearLayoutManager(context);
-
-        tagsView.onClick.subscribe { timeMinutesToErase ->
-            UIDialogs.showConfirmationDialog(requireContext(), getString(R.string.are_you_sure_delete_historical), {
-                StateHistory.instance.removeHistoryRange(timeMinutesToErase.second as Long);
-                UIDialogs.toast(view.context, timeMinutesToErase.first + " " + getString(R.string.removed));
-                adapter.updateFilteredVideos();
-                adapter.notifyDataSetChanged();
-            });
-        };
-
-        clearSearch.setOnClickListener {
-            editSearch.text.clear();
-            clearSearch.visibility = View.GONE;
-            adapter.setQuery("");
-            editSearch.clearFocus();
-            inputMethodManager.hideSoftInputFromWindow(editSearch.windowToken, 0);
-        };
-
-        editSearch.addTextChangedListener { _ ->
-            val text = editSearch.text;
-            clearSearch.visibility = if (text.isEmpty()) { View.GONE } else { View.VISIBLE };
-            adapter.setQuery(text.toString());
-        };
-
+        val view = HistoryView(this, inflater);
+        _view = view;
         return view;
     }
 
     override fun onDestroyMainView() {
         super.onDestroyMainView();
-        _adapter?.cleanup();
-        _adapter = null;
+        _view = null;
+    }
+
+    override fun onShownWithView(parameter: Any?, isBack: Boolean) {
+        super.onShownWithView(parameter, isBack)
+        _view?.setPager(StateHistory.instance.getHistoryPager());
+    }
+
+    @SuppressLint("ViewConstructor")
+    class HistoryView : LinearLayout {
+        private val _fragment: HistoryFragment;
+        private val _adapter: InsertedViewAdapterWithLoader<HistoryListViewHolder>;
+        private val _recyclerHistory: RecyclerView;
+        private val _clearSearch: ImageButton;
+        private val _editSearch: EditText;
+        private val _tagsView: TagsView;
+        private val _llmHistory: LinearLayoutManager;
+        private val _pagerLock = Object();
+        private var _nextPageHandler: TaskHandler<IPager<HistoryVideo>, List<HistoryVideo>>;
+        private var _pager: IPager<HistoryVideo>? = null;
+        private val _results = arrayListOf<HistoryVideo>();
+        private var _loading = false;
+
+        private var _automaticNextPageCounter = 0;
+
+        constructor(fragment: HistoryFragment, inflater: LayoutInflater) : super(inflater.context) {
+            _fragment = fragment;
+            inflater.inflate(R.layout.fragment_history, this);
+
+            _recyclerHistory = findViewById(R.id.recycler_history);
+            _clearSearch = findViewById(R.id.button_clear_search);
+            _editSearch = findViewById(R.id.edit_search);
+            _tagsView = findViewById(R.id.tags_text);
+            _tagsView.setPairs(listOf(
+                Pair(context.getString(R.string.last_hour), 60L),
+                Pair(context.getString(R.string.last_24_hours), 24L * 60L),
+                Pair(context.getString(R.string.last_week), 7L * 24L * 60L),
+                Pair(context.getString(R.string.last_30_days), 30L * 24L * 60L),
+                Pair(context.getString(R.string.last_year), 365L * 30L * 24L * 60L),
+                Pair(context.getString(R.string.all_time), -1L)
+            ));
+
+            _adapter = InsertedViewAdapterWithLoader(context, arrayListOf(), arrayListOf(),
+                { _results.size },
+                { view, _ ->
+                    val holder = HistoryListViewHolder(view);
+                    holder.onRemove.subscribe(::onHistoryVideoRemove);
+                    holder.onClick.subscribe(::onHistoryVideoClick);
+                    return@InsertedViewAdapterWithLoader holder;
+                },
+                { viewHolder, position ->
+                    var watchTime: String? = null;
+                    if (position == 0) {
+                        watchTime = _results[position].date.toHumanNowDiffStringMinDay();
+                    } else {
+                        val previousWatchTime = _results[position - 1].date.toHumanNowDiffStringMinDay();
+                        val currentWatchTime = _results[position].date.toHumanNowDiffStringMinDay();
+                        if (previousWatchTime != currentWatchTime) {
+                            watchTime = currentWatchTime;
+                        }
+                    }
+
+                    viewHolder.bind(_results[position], watchTime);
+                }
+            );
+
+            _recyclerHistory.adapter = _adapter;
+            _recyclerHistory.isSaveEnabled = false;
+            _llmHistory = LinearLayoutManager(context);
+            _recyclerHistory.layoutManager = _llmHistory;
+
+            _tagsView.onClick.subscribe { timeMinutesToErase ->
+                UIDialogs.showConfirmationDialog(context, context.getString(R.string.are_you_sure_delete_historical), {
+                    StateHistory.instance.removeHistoryRange(timeMinutesToErase.second as Long);
+                    UIDialogs.toast(context, timeMinutesToErase.first + " " + context.getString(R.string.removed));
+                    updatePager();
+                });
+            };
+
+            _clearSearch.setOnClickListener {
+                val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
+                _editSearch.text.clear();
+                _clearSearch.visibility = View.GONE;
+                setPager(StateHistory.instance.getHistoryPager());
+                _editSearch.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(_editSearch.windowToken, 0);
+            };
+
+            _editSearch.addTextChangedListener { _ ->
+                val text = _editSearch.text;
+                _clearSearch.visibility = if (text.isEmpty()) { View.GONE } else { View.VISIBLE };
+                updatePager();
+            };
+
+            _recyclerHistory.addOnScrollListener(object : RecyclerView.OnScrollListener() {
+                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+                    super.onScrolled(recyclerView, dx, dy);
+
+                    val visibleItemCount = _recyclerHistory.childCount;
+                    val firstVisibleItem = _llmHistory.findFirstVisibleItemPosition();
+
+                    Logger.i(TAG, "onScrolled _loading = $_loading, firstVisibleItem = $firstVisibleItem, visibleItemCount = $visibleItemCount, _results.size = ${_results.size}")
+
+                    val visibleThreshold = 15;
+                    if (!_loading && firstVisibleItem + visibleItemCount + visibleThreshold >= _results.size && firstVisibleItem > 0) {
+                        loadNextPage();
+                    }
+                }
+            });
+
+            _nextPageHandler = TaskHandler<IPager<HistoryVideo>, List<HistoryVideo>>({fragment.lifecycleScope}, {
+                if (it is IAsyncPager<*>)
+                    it.nextPageAsync();
+                else
+                    it.nextPage();
+
+                return@TaskHandler it.getResults();
+            }).success {
+                setLoading(false);
+
+                val posBefore = _results.size;
+                _results.addAll(it);
+                _adapter.notifyItemRangeInserted(_adapter.childToParentPosition(posBefore), it.size);
+                ensureEnoughContentVisible(it)
+            }.exception<Throwable> {
+                Logger.w(TAG, "Failed to load next page.", it);
+                UIDialogs.showGeneralRetryErrorDialog(context, context.getString(R.string.failed_to_load_next_page), it, {
+                    loadNextPage();
+                });
+            };
+        }
+
+        private fun updatePager() {
+            val query = _editSearch.text.toString();
+            if (_editSearch.text.isNotEmpty()) {
+                setPager(StateHistory.instance.getHistorySearchPager(query));
+            } else {
+                setPager(StateHistory.instance.getHistoryPager());
+            }
+        }
+
+        fun setPager(pager: IPager<HistoryVideo>) {
+            synchronized(_pagerLock) {
+                loadPagerInternal(pager);
+            }
+        }
+
+        private fun onHistoryVideoRemove(v: HistoryVideo) {
+            val index = _results.indexOf(v);
+            if (index == -1) {
+                return;
+            }
+
+            StateHistory.instance.removeHistory(v.video.url);
+            _results.removeAt(index);
+            _adapter.notifyItemRemoved(index);
+        }
+
+        private fun onHistoryVideoClick(v: HistoryVideo) {
+            val index = _results.indexOf(v);
+            if (index == -1) {
+                return;
+            }
+
+            _results.removeAt(index);
+            _results.add(0, v);
+
+            _adapter.notifyItemMoved(index, 0);
+            _adapter.notifyItemRangeChanged(0, 2);
+
+            val inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
+            val diff = v.video.duration - v.position;
+            val vid: Any = if (diff > 5) { v.video.withTimestamp(v.position) } else { v.video };
+            StatePlayer.instance.clearQueue();
+            _fragment.navigate<VideoDetailFragment>(vid).maximizeVideoDetail();
+            _editSearch.clearFocus();
+            inputMethodManager.hideSoftInputFromWindow(_editSearch.windowToken, 0);
+        }
+
+        private fun loadNextPage() {
+            synchronized(_pagerLock) {
+                val pager: IPager<HistoryVideo> = _pager ?: return;
+                val hasMorePages = pager.hasMorePages();
+                Logger.i(TAG, "loadNextPage() hasMorePages=$hasMorePages");
+
+                if (pager.hasMorePages()) {
+                    setLoading(true);
+                    _nextPageHandler.run(pager);
+                }
+            }
+        }
+
+        private fun setLoading(loading: Boolean) {
+            Logger.v(TAG, "setLoading loading=${loading}");
+            _loading = loading;
+            _adapter.setLoading(loading);
+        }
+
+        private fun loadPagerInternal(pager: IPager<HistoryVideo>) {
+            Logger.i(TAG, "Setting new internal pager on feed");
+
+            _results.clear();
+            val toAdd = pager.getResults();
+            _results.addAll(toAdd);
+            _adapter.notifyDataSetChanged();
+            ensureEnoughContentVisible(toAdd)
+            _pager = pager;
+        }
+
+        private fun ensureEnoughContentVisible(results: List<HistoryVideo>) {
+            val canScroll = if (_results.isEmpty()) false else {
+                val layoutManager = _llmHistory
+                val firstVisibleItemPosition = layoutManager.findFirstVisibleItemPosition()
+
+                if (firstVisibleItemPosition != RecyclerView.NO_POSITION) {
+                    val firstVisibleView = layoutManager.findViewByPosition(firstVisibleItemPosition)
+                    val itemHeight = firstVisibleView?.height ?: 0
+                    val occupiedSpace = _results.size * itemHeight
+                    val recyclerViewHeight = _recyclerHistory.height
+                    Logger.i(TAG, "ensureEnoughContentVisible loadNextPage occupiedSpace=$occupiedSpace recyclerViewHeight=$recyclerViewHeight")
+                    occupiedSpace >= recyclerViewHeight
+                } else {
+                    false
+                }
+
+            }
+
+            Logger.i(TAG, "ensureEnoughContentVisible loadNextPage canScroll=$canScroll _automaticNextPageCounter=$_automaticNextPageCounter")
+            if (!canScroll || results.isEmpty()) {
+                _automaticNextPageCounter++
+                if(_automaticNextPageCounter <= 4)
+                    loadNextPage()
+            } else {
+                _automaticNextPageCounter = 0;
+            }
+        }
     }
 
     companion object {
         fun newInstance() = HistoryFragment().apply {}
+        private const val TAG = "HistoryFragment"
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListAdapter.kt
deleted file mode 100644
index 33335ade..00000000
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListAdapter.kt
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.futo.platformplayer.views.adapters
-
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import com.futo.platformplayer.*
-import com.futo.platformplayer.api.media.structures.IPager
-import com.futo.platformplayer.constructs.Event1
-import com.futo.platformplayer.models.HistoryVideo
-import com.futo.platformplayer.states.StateApp
-import com.futo.platformplayer.states.StateHistory
-import com.futo.platformplayer.states.StatePlaylists
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
-
-class HistoryListAdapter : RecyclerView.Adapter<HistoryListViewHolder> {
-    private lateinit var _filteredVideos: MutableList<HistoryVideo>;
-
-    val onClick = Event1<HistoryVideo>();
-    private var _query: String = "";
-
-    constructor() : super() {
-        updateFilteredVideos();
-
-        StateHistory.instance.onHistoricVideoChanged.subscribe(this) { video, position ->
-            StateApp.instance.scope.launch(Dispatchers.Main) {
-                val index = _filteredVideos.indexOfFirst { v -> v.video.url == video.url };
-                if (index == -1) {
-                    return@launch;
-                }
-
-                _filteredVideos[index].position = position;
-                if (index < _filteredVideos.size - 2) {
-                    notifyItemRangeChanged(index, 2);
-                } else {
-                    notifyItemChanged(index);
-                }
-            }
-        };
-    }
-
-    fun setQuery(query: String) {
-        _query = query;
-        updateFilteredVideos();
-    }
-
-    fun updateFilteredVideos() {
-        val videos = StateHistory.instance.getHistory();
-        //filtered val pager = StateHistory.instance.getHistorySearchPager("querrryyyyy"); TODO: Implement pager
-
-        if (_query.isBlank()) {
-            _filteredVideos = videos.toMutableList();
-        } else {
-            _filteredVideos = videos.filter { v -> v.video.name.lowercase().contains(_query); }.toMutableList();
-        }
-
-        notifyDataSetChanged();
-    }
-
-    fun cleanup() {
-        StateHistory.instance.onHistoricVideoChanged.remove(this);
-    }
-
-    override fun getItemCount() = _filteredVideos.size;
-
-    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): HistoryListViewHolder {
-        val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.list_history, viewGroup, false);
-        val holder = HistoryListViewHolder(view);
-
-        holder.onRemove.subscribe { v ->
-            val videos = _filteredVideos;
-            val index = videos.indexOf(v);
-            if (index == -1) {
-                return@subscribe;
-            }
-
-            StateHistory.instance.removeHistory(v.video.url);
-            _filteredVideos.removeAt(index);
-            notifyItemRemoved(index);
-        };
-        holder.onClick.subscribe { v ->
-            val videos = _filteredVideos;
-            val index = videos.indexOf(v);
-            if (index == -1) {
-                return@subscribe;
-            }
-
-            _filteredVideos.removeAt(index);
-            _filteredVideos.add(0, v);
-
-            notifyItemMoved(index, 0);
-            notifyItemRangeChanged(0, 2);
-            onClick.emit(v);
-        };
-
-        return holder;
-    }
-
-    override fun onBindViewHolder(viewHolder: HistoryListViewHolder, position: Int) {
-        val videos = _filteredVideos;
-        var watchTime: String? = null;
-        if (position == 0) {
-            watchTime = videos[position].date.toHumanNowDiffStringMinDay();
-        } else {
-            val previousWatchTime = videos[position - 1].date.toHumanNowDiffStringMinDay();
-            val currentWatchTime = videos[position].date.toHumanNowDiffStringMinDay();
-            if (previousWatchTime != currentWatchTime) {
-                watchTime = currentWatchTime;
-            }
-        }
-
-        viewHolder.bind(videos[position], watchTime);
-    }
-
-    companion object {
-        val TAG = "HistoryListAdapter";
-    }
-}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListViewHolder.kt
index 7194c1e0..2f018c9d 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/HistoryListViewHolder.kt
@@ -1,6 +1,8 @@
 package com.futo.platformplayer.views.adapters
 
+import android.view.LayoutInflater
 import android.view.View
+import android.view.ViewGroup
 import android.widget.ImageButton
 import android.widget.ImageView
 import android.widget.LinearLayout
@@ -35,26 +37,26 @@ class HistoryListViewHolder : ViewHolder {
     val onClick = Event1<HistoryVideo>();
     val onRemove = Event1<HistoryVideo>();
 
-    constructor(view: View) : super(view) {
-        _root = view.findViewById(R.id.root);
-        _imageThumbnail = view.findViewById(R.id.image_video_thumbnail);
-        _imageThumbnail?.clipToOutline = true;
-        _textName = view.findViewById(R.id.text_video_name);
-        _textAuthor = view.findViewById(R.id.text_author);
-        _textMetadata = view.findViewById(R.id.text_video_metadata);
-        _textVideoDuration = view.findViewById(R.id.thumbnail_duration);
-        _containerDuration = view.findViewById(R.id.thumbnail_duration_container);
-        _containerLive = view.findViewById(R.id.thumbnail_live_container);
-        _imageRemove = view.findViewById(R.id.image_trash);
-        _textHeader = view.findViewById(R.id.text_header);
-        _timeBar = view.findViewById(R.id.time_bar);
+    constructor(viewGroup: ViewGroup) : super(LayoutInflater.from(viewGroup.context).inflate(R.layout.list_history, viewGroup, false)) {
+        _root = itemView.findViewById(R.id.root);
+        _imageThumbnail = itemView.findViewById(R.id.image_video_thumbnail);
+        _imageThumbnail.clipToOutline = true;
+        _textName = itemView.findViewById(R.id.text_video_name);
+        _textAuthor = itemView.findViewById(R.id.text_author);
+        _textMetadata = itemView.findViewById(R.id.text_video_metadata);
+        _textVideoDuration = itemView.findViewById(R.id.thumbnail_duration);
+        _containerDuration = itemView.findViewById(R.id.thumbnail_duration_container);
+        _containerLive = itemView.findViewById(R.id.thumbnail_live_container);
+        _imageRemove = itemView.findViewById(R.id.image_trash);
+        _textHeader = itemView.findViewById(R.id.text_header);
+        _timeBar = itemView.findViewById(R.id.time_bar);
 
         _root.setOnClickListener {
             val v = video ?: return@setOnClickListener;
             onClick.emit(v);
         };
 
-        _imageRemove?.setOnClickListener {
+        _imageRemove.setOnClickListener {
             val v = video ?: return@setOnClickListener;
             onRemove.emit(v);
         };
-- 
GitLab