sadr0b0t / yashlang

PeerTube and YouTube player for Android with local playlists and whitelisted recommendations
GNU General Public License v3.0
51 stars 3 forks source link

Не обновляются статусы элементов списка если вернуться в список из экрана, следующего за ним #136

Closed sadr0b0t closed 2 years ago

sadr0b0t commented 2 years ago

Например: в настройках список плейлистов (плейлисты отмечены переключателями вкл/выкл) > кликнуть на плейлист (перейти в настройки конкретного плейлиста), выключить плейлист (или включить) на этом экране > вернуться в список плейлистов > переключатель в списке не получит актуальное значение.

Аналогично: состояние "звездочка" для роликов видео - если открыть ролик из экрана "Поиск" или из экрана "Плейлист" - не обновляется в списке, если вернуться в него из экрана плеера, на котором флаг "звездочка" можно поменять. Но: состояние обновиться в списке "История" или "Любимое" (в любомом выключенный ролик просто изсчезнет из списка).

Скорее всего отвалилось после этой оптимизации: https://github.com/sadr0b0t/yashlang/issues/129 , т.к. раньше все списком обновлялись целиком на любой чих, а сейчас изменения идут точечно, т.е. какое-то событие на обновление могли и пропустить.

sadr0b0t commented 2 years ago

https://github.com/sadr0b0t/yashlang/commit/053ff9d6a1f846ab1bb98d4ac9ceb58bc5f19140 https://github.com/sadr0b0t/yashlang/commit/9247a067bbfafdc169ca7f0ff712a6581e94588b

Фикс.

Основная причина истории - реализация DIFF_CALLBACK areContentsTheSame, которая должна выглядеть примерно вот так:

                @Override
                public boolean areContentsTheSame(VideoItem oldItem, VideoItem newItem) {
                    // вставим небольшой хак, чтобы не моргала иконка обновленного элемента -
                    // перекинем кэш загруженной иконки со старого элемента на новый элемент,
                    // раз уж он к нам сюда пришел
                    newItem.setThumbBitmap(oldItem.getThumbBitmap());

                    // Здесь следует перечислить все поля, которые в том или ином виде
                    // отображены на элементе списка: например, прогресс (pausedAt), или
                    // статус "любомое" (starred). В таком случае при изменении этих полей
                    // (например, при сохранении новой позиции или переключении состояния
                    // звездочки) будет автоматически изменяться состояние элемента в загруженном
                    // списке (на текущем экране - например, в рекомендациях на экране плеера,
                    // или в списке на экране, из которого был открыт плеер)
                    // Но внесем сюда только изменяемые позиции (имя или адрес ролика не изменяются,
                    // поэтому сравнивать дополнительно их нет большого смысла)
                    return (oldItem.isStarred() == newItem.isStarred() &&
                            oldItem.getPausedAt() == newItem.getPausedAt() &&
                            oldItem.isHasOffline() == newItem.isHasOffline() &&
                            oldItem.isBlacklisted() == newItem.isBlacklisted() &&
                            oldItem.isEnabled() == newItem.isEnabled() &&
                            oldItem.getViewCount() == newItem.getViewCount() &&
                            ( (oldItem.getLastViewedDate() != null && newItem.getLastViewedDate() != null &&
                                    oldItem.getLastViewedDate().equals(newItem.getLastViewedDate())) ||
                                    (oldItem.getLastViewedDate() == null && newItem.getLastViewedDate() == null) ) &&
                            ( (oldItem.getStarredDate() != null && newItem.getStarredDate() != null &&
                                    oldItem.getStarredDate().equals(newItem.getStarredDate())) ||
                                    (oldItem.getStarredDate() == null && newItem.getStarredDate() == null) ) );
                }

Иначе события из базы данных ловятся, но метод onBindViewHolder не вызывается (раньше похоже, действительно, все эти проблемы скрывал notifyDataSetChanged).

В SearchVideoActivtiy дополнительно еще обрубал videoItemsLiveData.removeObservers(this) в onPause, поэтому он просто переставал получать любые события после переключения экрана.

На самом деле, вручную управлять videoItemsLiveData не нужно - он сам всё в нужный момент сделает. https://stackoverflow.com/questions/63737845/when-should-i-remove-livedata-observer-on-android#63738811 https://developer.android.com/topic/libraries/architecture/livedata#the_advantages_of_using_livedata

Дополнительный бонус изменений - элементы в списке рекомендаций теперь изменяются автоматом при любых обновлениях соответствующих роликов (например, если в рекомендациях видно текущий ролик, внизу в этом списке появится звездочка, если установить звездочку на ролики, или обновится прогресс, если переместить ползунок проигрыания, или появится иконка "дискетка" после того, как у ролика докачается кэш потока в фоне; или если заблокировать текущий ролик, он сам улетит и из рекомендаций).

Но только не для случайных рекомендаций при обычном открытии ролика, т.к. там используется VideoItemArrayAdapter, а не VideoItemPagedListAdapter. Следует реализовать эти измения для ArrayAdapter в ручном режиме или использовать PagedListAdapter вместо ArrayAdapter (так просто это не сделать; в любом случае - в другом тикете).

sadr0b0t commented 2 years ago

Еще заметил: если в рекомендациях в режиме "любимое" убрать звезду с ролика, он исчезнет из рекомендаций, а если поставить обратно (не переключая ролик), то он обратно не появится