comments: implement dialog

This commit is contained in:
Yuriy Liskov
2023-01-01 09:53:26 +02:00
parent cbd8ee9e54
commit e6b386bdfc
18 changed files with 260 additions and 37 deletions

View File

@ -160,8 +160,13 @@ public class MessagesListAdapter<MESSAGE extends IMessage>
Wrapper<MESSAGE> element = new Wrapper<>(message);
items.add(0, element);
notifyItemRangeInserted(0, isNewMessageToday ? 2 : 1);
if (layoutManager != null && scroll) {
layoutManager.scrollToPosition(0);
//if (layoutManager != null && scroll) {
// layoutManager.scrollToPosition(0);
//}
if (layoutManager != null) {
// TODO: Remember position when user performs manual scrolling
layoutManager.scrollToPosition(scroll ? 0 : items.size() - 1);
}
trimEnd();

View File

@ -52,7 +52,7 @@ public class MainPlayerEventBridge implements PlayerEventListener {
VideoStateManager stateUpdater = new VideoStateManager();
ContentBlockManager contentBlockManager = new ContentBlockManager();
LiveChatManager liveChatManager = new LiveChatManager();
//CommentsManager commentsManager = new CommentsManager();
CommentsManager commentsManager = new CommentsManager();
RemoteControlManager commandManager = new RemoteControlManager(context, suggestionsLoader, videoLoader);
HQDialogManager hqDialogManager = new HQDialogManager(stateUpdater);
@ -63,7 +63,7 @@ public class MainPlayerEventBridge implements PlayerEventListener {
suggestionsLoader.addMetadataListener(stateUpdater);
suggestionsLoader.addMetadataListener(contentBlockManager);
suggestionsLoader.addMetadataListener(liveChatManager);
//suggestionsLoader.addMetadataListener(commentsManager);
suggestionsLoader.addMetadataListener(commentsManager);
// NOTE: position matters!!!
mEventListeners.add(autoFrameRateManager);
@ -75,6 +75,7 @@ public class MainPlayerEventBridge implements PlayerEventListener {
mEventListeners.add(commandManager);
mEventListeners.add(contentBlockManager);
mEventListeners.add(liveChatManager);
mEventListeners.add(commentsManager);
}
public static MainPlayerEventBridge instance(Context context) {

View File

@ -1,12 +1,16 @@
package com.liskovsoft.smartyoutubetv2.common.app.models.playback.managers;
import com.liskovsoft.mediaserviceinterfaces.CommentsService;
import com.liskovsoft.mediaserviceinterfaces.data.CommentGroup;
import com.liskovsoft.mediaserviceinterfaces.data.CommentItem;
import com.liskovsoft.mediaserviceinterfaces.data.MediaItemMetadata;
import com.liskovsoft.sharedutils.mylogger.Log;
import com.liskovsoft.sharedutils.rx.RxUtils;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.PlayerEventListenerHelper;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.controller.PlaybackUIController;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.managers.SuggestionsLoaderManager.MetadataListener;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.ui.CommentsReceiver;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.ui.UiOptionItem;
import com.liskovsoft.smartyoutubetv2.common.app.presenters.AppDialogPresenter;
import com.liskovsoft.youtubeapi.service.YouTubeMediaService;
import io.reactivex.disposables.Disposable;
@ -40,36 +44,45 @@ public class CommentsManager extends PlayerEventListenerHelper implements Metada
return;
}
CommentsReceiver commentsReceiver = new CommentsReceiver() {
private Callback mCallback;
@Override
public void addCommentGroup(CommentGroup commentGroup) {
if (mCallback != null) {
mCallback.onCommentGroup(commentGroup);
}
}
@Override
public void setCallback(Callback callback) {
mCallback = callback;
}
@Override
public void onGroupEnd(CommentGroup commentGroup) {
}
@Override
public void onCommentClicked(CommentItem commentItem) {
}
};
AppDialogPresenter appDialogPresenter = AppDialogPresenter.instance(getActivity());
String title = getController().getVideo().getTitle();
appDialogPresenter.appendCommentsCategory(title, UiOptionItem.from(title, commentsReceiver));
appDialogPresenter.showDialog();
mCommentsAction = mCommentsService.getCommentsObserve(mCommentsKey)
.subscribe(
commentGroup -> {
AppDialogPresenter appDialogPresenter = AppDialogPresenter.instance(getActivity());
//appDialogPresenter.appendChatCategory();
appDialogPresenter.showDialog();
},
commentsReceiver::addCommentGroup,
error -> {
Log.e(TAG, error.getMessage());
error.printStackTrace();
}
);
//ChatReceiver chatReceiver = new ChatReceiverImpl();
//getController().setChatReceiver(chatReceiver);
//
//mCommentsAction = mChatService.openLiveChatObserve(mLiveChatKey)
// .subscribe(
// chatItem -> {
// Log.d(TAG, chatItem.getMessage());
// if (checkItem(chatItem)) {
// chatReceiver.addChatItem(chatItem);
// }
// },
// error -> {
// Log.e(TAG, error.getMessage());
// error.printStackTrace();
// },
// () -> Log.e(TAG, "Live chat session has been closed")
// );
}
@Override

View File

@ -1,7 +1,5 @@
package com.liskovsoft.smartyoutubetv2.common.app.models.playback.managers;
import android.os.Handler;
import android.os.Looper;
import com.liskovsoft.mediaserviceinterfaces.MediaItemService;
import com.liskovsoft.mediaserviceinterfaces.MediaService;
import com.liskovsoft.mediaserviceinterfaces.data.MediaItemFormatInfo;
@ -10,15 +8,14 @@ import com.liskovsoft.sharedutils.helpers.MessageHelpers;
import com.liskovsoft.sharedutils.mylogger.Log;
import com.liskovsoft.sharedutils.rx.RxUtils;
import com.liskovsoft.smartyoutubetv2.common.R;
import com.liskovsoft.smartyoutubetv2.common.app.models.data.SampleMediaItem;
import com.liskovsoft.smartyoutubetv2.common.app.models.data.Playlist;
import com.liskovsoft.smartyoutubetv2.common.app.models.data.SampleMediaItem;
import com.liskovsoft.smartyoutubetv2.common.app.models.data.Video;
import com.liskovsoft.smartyoutubetv2.common.app.models.data.VideoGroup;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.PlayerEventListenerHelper;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.controller.PlaybackUIController;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.listener.PlayerEventListener;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.managers.SuggestionsLoaderManager.MetadataListener;
import com.liskovsoft.smartyoutubetv2.common.app.presenters.ChannelPresenter;
import com.liskovsoft.smartyoutubetv2.common.app.presenters.dialogs.VideoActionPresenter;
import com.liskovsoft.smartyoutubetv2.common.misc.MediaServiceManager;
import com.liskovsoft.smartyoutubetv2.common.prefs.DataChangeBase.OnDataChange;
@ -29,9 +26,7 @@ import com.liskovsoft.smartyoutubetv2.common.utils.AppDialogUtil;
import com.liskovsoft.smartyoutubetv2.common.utils.UniqueRandom;
import com.liskovsoft.smartyoutubetv2.common.utils.Utils;
import com.liskovsoft.youtubeapi.service.YouTubeMediaService;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import java.util.Collections;
import java.util.HashMap;

View File

@ -0,0 +1,14 @@
package com.liskovsoft.smartyoutubetv2.common.app.models.playback.ui;
import com.liskovsoft.mediaserviceinterfaces.data.CommentGroup;
import com.liskovsoft.mediaserviceinterfaces.data.CommentItem;
public interface CommentsReceiver {
interface Callback {
void onCommentGroup(CommentGroup commentGroup);
}
void addCommentGroup(CommentGroup commentGroup);
void setCallback(Callback callback);
void onGroupEnd(CommentGroup commentGroup);
void onCommentClicked(CommentItem commentItem);
}

View File

@ -12,4 +12,5 @@ public interface OptionItem {
void setRadio(OptionItem... items);
OptionItem[] getRadio();
ChatReceiver getChatReceiver();
CommentsReceiver getCommentsReceiver();
}

View File

@ -16,6 +16,7 @@ public class UiOptionItem implements OptionItem {
private OptionItem[] mRequiredItems;
private OptionItem[] mRadioItems;
private ChatReceiver mChatReceiver;
private CommentsReceiver mCommentsReceiver;
public static List<OptionItem> from(List<FormatItem> formats, OptionCallback callback) {
return from(formats, callback, null);
@ -94,6 +95,14 @@ public class UiOptionItem implements OptionItem {
return uiOptionItem;
}
public static OptionItem from(CharSequence title, CommentsReceiver commentsReceiver) {
UiOptionItem uiOptionItem = new UiOptionItem();
uiOptionItem.mTitle = title;
uiOptionItem.mCommentsReceiver = commentsReceiver;
return uiOptionItem;
}
public static FormatItem toFormat(OptionItem option) {
if (option instanceof UiOptionItem) {
return ((UiOptionItem) option).mFormat;
@ -168,4 +177,9 @@ public class UiOptionItem implements OptionItem {
public ChatReceiver getChatReceiver() {
return mChatReceiver;
}
@Override
public CommentsReceiver getCommentsReceiver() {
return mCommentsReceiver;
}
}

View File

@ -45,6 +45,10 @@ public class AppDialogPresenter extends BasePresenter<AppDialogView> {
return new OptionCategory(title, Collections.singletonList(item), TYPE_CHAT);
}
public static OptionCategory comments(String title, OptionItem item) {
return new OptionCategory(title, Collections.singletonList(item), TYPE_COMMENTS);
}
public static OptionCategory singleSwitch(OptionItem item) {
ArrayList<OptionItem> items = new ArrayList<>();
items.add(item);
@ -70,6 +74,7 @@ public class AppDialogPresenter extends BasePresenter<AppDialogView> {
public static final int TYPE_STRING_LIST = 4;
public static final int TYPE_LONG_TEXT = 5;
public static final int TYPE_CHAT = 6;
public static final int TYPE_COMMENTS = 7;
public int type;
public String title;
public List<OptionItem> items;
@ -195,6 +200,10 @@ public class AppDialogPresenter extends BasePresenter<AppDialogView> {
mCategories.add(OptionCategory.chat(categoryTitle, item));
}
public void appendCommentsCategory(String categoryTitle, OptionItem item) {
mCategories.add(OptionCategory.comments(categoryTitle, item));
}
public void appendSingleSwitch(OptionItem optionItem) {
mCategories.add(OptionCategory.singleSwitch(optionItem));
}

View File

@ -444,7 +444,7 @@
<string name="sources">Исходники</string>
<string name="releases">Релизы</string>
<string name="prefer_avc_over_vp9">Выбор кодека: отдавать предпочтение avc над vp9</string>
<string name="open_chat">Чат</string>
<string name="open_chat">Чат/Комментарии</string>
<string name="place_chat_left">Разместить чат слева</string>
<string name="use_alt_speech_recognizer">Альтернативный распознаватель речи</string>
<string name="time_format">Формат времени</string>

View File

@ -444,7 +444,7 @@
<string name="sources">Вихідний код</string>
<string name="releases">Релізи</string>
<string name="prefer_avc_over_vp9">Вибір кодека: віддавати перевагу avc над vp9</string>
<string name="open_chat">Чат</string>
<string name="open_chat">Чат/Коментарі</string>
<string name="place_chat_left">Розмістити чат ліворуч</string>
<string name="use_alt_speech_recognizer">Альтернативний розпізнавач мови</string>
<string name="time_format">Формат часу</string>

View File

@ -452,7 +452,7 @@
<string name="sources">Sources</string>
<string name="releases">Releases</string>
<string name="prefer_avc_over_vp9">Codec selection: prefer avc over vp9</string>
<string name="open_chat">Chat</string>
<string name="open_chat">Chat/Comments</string>
<string name="place_chat_left">Place chat to the left</string>
<string name="use_alt_speech_recognizer">Alt speech recognizer</string>
<string name="time_format">Time format</string>

View File

@ -22,6 +22,8 @@ import com.liskovsoft.smartyoutubetv2.common.app.views.AppDialogView;
import com.liskovsoft.smartyoutubetv2.common.utils.Utils;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.ChatPreference;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.ChatPreferenceDialogFragment;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.CommentsPreference;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.CommentsPreferenceDialogFragment;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.RadioListPreferenceDialogFragment;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.StringListPreference;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.StringListPreferenceDialogFragment;
@ -148,6 +150,14 @@ public class AppDialogFragment extends LeanbackSettingsFragment
f.setTargetFragment(caller, 0);
startPreferenceFragment(f);
return true;
} else if (pref instanceof CommentsPreference) {
CommentsPreference commentsPreference = (CommentsPreference) pref;
CommentsPreferenceDialogFragment f = CommentsPreferenceDialogFragment.newInstance(commentsPreference.getCommentsReceiver(), commentsPreference.getKey());
f.enableTransparent(mIsTransparent);
f.setTargetFragment(caller, 0);
startPreferenceFragment(f);
return true;
}

View File

@ -13,6 +13,7 @@ import com.liskovsoft.smartyoutubetv2.common.app.presenters.AppDialogPresenter.O
import com.liskovsoft.smartyoutubetv2.common.utils.Utils;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.ChatPreference;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.CommentsPreference;
import com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other.StringListPreference;
import java.util.HashSet;
@ -62,6 +63,8 @@ public class AppDialogFragmentManager {
return createLongTextPreference(category);
case OptionCategory.TYPE_CHAT:
return createChatPreference(category);
case OptionCategory.TYPE_COMMENTS:
return createCommentsPreference(category);
}
throw new IllegalStateException("Can't find matched preference for type: " + category.type);
@ -96,6 +99,17 @@ public class AppDialogFragmentManager {
return pref;
}
private Preference createCommentsPreference(OptionCategory category) {
CommentsPreference pref = new CommentsPreference(mStyledContext);
OptionItem optionItem = category.items.get(0);
pref.setCommentsReceiver(optionItem.getCommentsReceiver());
initDialogPreference(category, pref);
return pref;
}
public Preference createButtonPreference(OptionCategory category) {
Preference result = null;

View File

@ -0,0 +1,34 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.DialogPreference;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.ui.CommentsReceiver;
public class CommentsPreference extends DialogPreference {
private CommentsReceiver mCommentsReceiver;
public CommentsPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CommentsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CommentsPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CommentsPreference(Context context) {
super(context);
}
public void setCommentsReceiver(CommentsReceiver commentsReceiver) {
mCommentsReceiver = commentsReceiver;
}
public CommentsReceiver getCommentsReceiver() {
return mCommentsReceiver;
}
}

View File

@ -0,0 +1,88 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.dialogs.other;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.leanback.preference.LeanbackPreferenceDialogFragment;
import androidx.preference.DialogPreference;
import com.bumptech.glide.Glide;
import com.liskovsoft.mediaserviceinterfaces.data.CommentItem;
import com.liskovsoft.smartyoutubetv2.common.app.models.playback.ui.CommentsReceiver;
import com.liskovsoft.smartyoutubetv2.tv.R;
import com.liskovsoft.smartyoutubetv2.tv.ui.widgets.chat.ChatItemMessage;
import com.liskovsoft.smartyoutubetv2.tv.util.ViewUtil;
import com.stfalcon.chatkit.messages.MessagesList;
import com.stfalcon.chatkit.messages.MessagesListAdapter;
public class CommentsPreferenceDialogFragment extends LeanbackPreferenceDialogFragment {
private static final String SENDER_ID = CommentsPreferenceDialogFragment.class.getSimpleName();
private boolean mIsTransparent;
private CommentsReceiver mCommentsReceiver;
private CharSequence mDialogTitle;
public static CommentsPreferenceDialogFragment newInstance(CommentsReceiver commentsReceiver, String key) {
final Bundle args = new Bundle(1);
args.putString(ARG_KEY, key);
final CommentsPreferenceDialogFragment
fragment = new CommentsPreferenceDialogFragment();
fragment.setArguments(args);
fragment.mCommentsReceiver = commentsReceiver;
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
final DialogPreference preference = getPreference();
mDialogTitle = preference.getDialogTitle();
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.chat_preference_fragment, container,
false);
final CharSequence title = mDialogTitle;
if (!TextUtils.isEmpty(title)) {
final TextView titleView = (TextView) view.findViewById(R.id.decor_title);
titleView.setText(title);
}
MessagesList messagesList = (MessagesList) view.findViewById(R.id.messagesList);
MessagesListAdapter<ChatItemMessage> adapter = new MessagesListAdapter<>(SENDER_ID, (imageView, url, payload) ->
Glide.with(view.getContext())
.load(url)
.apply(ViewUtil.glideOptions())
.circleCrop() // resize image
.into(imageView));
messagesList.setAdapter(adapter);
if (mCommentsReceiver != null) {
mCommentsReceiver.setCallback(commentGroup -> {
for (CommentItem commentItem : commentGroup.getComments()) {
adapter.addToStart(ChatItemMessage.from(commentItem), false);
}
});
}
if (mIsTransparent) {
ViewUtil.enableTransparentDialog(getActivity(), view);
}
return view;
}
public void enableTransparent(boolean enable) {
mIsTransparent = enable;
}
}

View File

@ -1,6 +1,7 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.chat;
import com.liskovsoft.mediaserviceinterfaces.data.ChatItem;
import com.liskovsoft.mediaserviceinterfaces.data.CommentItem;
import com.stfalcon.chatkit.commons.models.IUser;
public class ChatItemAuthor implements IUser {
@ -17,6 +18,15 @@ public class ChatItemAuthor implements IUser {
return author;
}
public static ChatItemAuthor from(CommentItem commentItem) {
ChatItemAuthor author = new ChatItemAuthor();
author.mAvatar = commentItem.getAuthorPhoto();
author.mName = commentItem.getAuthorName();
author.mId = commentItem.getAuthorName();
return author;
}
@Override
public String getId() {
return mId;

View File

@ -1,6 +1,8 @@
package com.liskovsoft.smartyoutubetv2.tv.ui.widgets.chat;
import com.liskovsoft.mediaserviceinterfaces.data.ChatItem;
import com.liskovsoft.mediaserviceinterfaces.data.CommentItem;
import com.liskovsoft.smartyoutubetv2.common.app.models.data.Video;
import com.stfalcon.chatkit.commons.models.IMessage;
import java.util.Date;
@ -23,6 +25,19 @@ public class ChatItemMessage implements IMessage {
return message;
}
public static ChatItemMessage from(CommentItem commentItem) {
ChatItemMessage message = new ChatItemMessage();
message.mId = commentItem.getId();
if (commentItem.getMessage() != null && !commentItem.getMessage().trim().isEmpty()) {
message.mText = String.format("%s %s %s: %s",
commentItem.getAuthorName(), Video.TERTIARY_TEXT_DELIM, commentItem.getPublishedDate(), commentItem.getMessage());
}
message.mAuthor = ChatItemAuthor.from(commentItem);
message.mCreatedAt = new Date();
return message;
}
@Override
public String getId() {
return mId;