aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/RPANComment.java15
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java22
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RPANCommentStreamRecyclerViewAdapter.java83
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java98
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java2
-rw-r--r--app/src/main/res/layout/exo_rpan_broadcast_playback_control_view.xml102
-rw-r--r--app/src/main/res/layout/fragment_view_rpan_broadcast.xml2
-rw-r--r--app/src/main/res/layout/item_rpan_comment.xml38
9 files changed, 358 insertions, 6 deletions
diff --git a/app/build.gradle b/app/build.gradle
index b817d23f..fab2da39 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -177,6 +177,8 @@ dependencies {
implementation 'androidx.palette:palette:1.0.0'
+ implementation 'com.tinder.scarlet:scarlet:0.1.12'
+
/**** Builds and flavors ****/
// debugImplementation because LeakCanary should only run in debug builds.
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RPANComment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RPANComment.java
new file mode 100644
index 00000000..077031bf
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RPANComment.java
@@ -0,0 +1,15 @@
+package ml.docilealligator.infinityforreddit;
+
+public class RPANComment {
+ public String author;
+ public String authorIconImage;
+ public String content;
+ public long createdUTC;
+
+ public RPANComment(String author, String authorIconImage, String content, long createdUTC) {
+ this.author = author;
+ this.authorIconImage = authorIconImage;
+ this.content = content;
+ this.createdUTC = createdUTC;
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java
index 57b419ee..c22d481f 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java
@@ -18,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
+import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
@@ -28,6 +29,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.concurrent.Executor;
@@ -217,7 +219,25 @@ public class RPANActivity extends AppCompatActivity {
sectionsPagerAdapter = new SectionsPagerAdapter(this);
viewPager2.setAdapter(sectionsPagerAdapter);
viewPager2.setOffscreenPageLimit(3);
- //fixViewPager2Sensitivity(viewPager2);
+ fixViewPager2Sensitivity(viewPager2);
+ }
+
+ private void fixViewPager2Sensitivity(ViewPager2 viewPager2) {
+ try {
+ Field recyclerViewField = ViewPager2.class.getDeclaredField("mRecyclerView");
+ recyclerViewField.setAccessible(true);
+
+ RecyclerView recyclerView = (RecyclerView) recyclerViewField.get(viewPager2);
+
+ Field touchSlopField = RecyclerView.class.getDeclaredField("mTouchSlop");
+ touchSlopField.setAccessible(true);
+
+ Object touchSlopBox = touchSlopField.get(recyclerView);
+ if (touchSlopBox != null) {
+ int touchSlop = (int) touchSlopBox;
+ touchSlopField.set(recyclerView, touchSlop * 4);
+ }
+ } catch (NoSuchFieldException | IllegalAccessException ignore) {}
}
private class SectionsPagerAdapter extends FragmentStateAdapter {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RPANCommentStreamRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RPANCommentStreamRecyclerViewAdapter.java
new file mode 100644
index 00000000..ba7dcd34
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/RPANCommentStreamRecyclerViewAdapter.java
@@ -0,0 +1,83 @@
+package ml.docilealligator.infinityforreddit.adapters;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.RequestManager;
+import com.bumptech.glide.request.RequestOptions;
+
+import java.util.ArrayList;
+
+import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
+import ml.docilealligator.infinityforreddit.R;
+import ml.docilealligator.infinityforreddit.RPANComment;
+
+public class RPANCommentStreamRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ private RequestManager glide;
+ private ArrayList<RPANComment> rpanComments;
+
+ public RPANCommentStreamRecyclerViewAdapter(Context context) {
+ glide = Glide.with(context);
+ rpanComments = new ArrayList<>();
+ }
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ return new RPANCommentViewHolder(LayoutInflater.from(parent.getContext()).inflate(
+ R.layout.item_rpan_comment, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ if (holder instanceof RPANCommentViewHolder) {
+ ((RPANCommentViewHolder) holder).authorTextView.setText(rpanComments.get(position).author);
+ ((RPANCommentViewHolder) holder).contentTextView.setText(rpanComments.get(position).content);
+ glide.load(rpanComments.get(position).authorIconImage)
+ .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
+ .error(glide.load(R.drawable.subreddit_default_icon)
+ .apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
+ .into(((RPANCommentViewHolder) holder).iconImageView);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return rpanComments == null ? 0 : rpanComments.size();
+ }
+
+ @Override
+ public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
+ super.onViewRecycled(holder);
+ if (holder instanceof RPANCommentViewHolder) {
+ glide.clear(((RPANCommentViewHolder) holder).iconImageView);
+ }
+ }
+
+ public void addRPANComment(RPANComment rpanComment) {
+ rpanComments.add(rpanComment);
+ notifyItemInserted(rpanComments.size() - 1);
+ }
+
+ class RPANCommentViewHolder extends RecyclerView.ViewHolder {
+ ImageView iconImageView;
+ TextView authorTextView;
+ TextView timeTextView;
+ TextView contentTextView;
+
+ public RPANCommentViewHolder(@NonNull View itemView) {
+ super(itemView);
+ iconImageView = itemView.findViewById(R.id.icon_image_view_item_rpan_comment);
+ authorTextView = itemView.findViewById(R.id.author_text_view_item_rpan_comment);
+ contentTextView = itemView.findViewById(R.id.content_text_view_item_rpan_comment);
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java
index 80f98cee..4eed627c 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java
@@ -2,8 +2,11 @@ package ml.docilealligator.infinityforreddit.fragments;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -11,7 +14,9 @@ import android.widget.ImageButton;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.RecyclerView;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayerFactory;
@@ -28,9 +33,14 @@ import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.ui.TrackSelectionDialogBuilder;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
-import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
import javax.inject.Inject;
import javax.inject.Named;
@@ -39,19 +49,30 @@ import butterknife.ButterKnife;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.RPANBroadcast;
+import ml.docilealligator.infinityforreddit.RPANComment;
+import ml.docilealligator.infinityforreddit.adapters.RPANCommentStreamRecyclerViewAdapter;
import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
+import ml.docilealligator.infinityforreddit.utils.JSONUtils;
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.WebSocket;
+import okhttp3.WebSocketListener;
public class ViewRPANBroadcastFragment extends Fragment {
public static final String EXTRA_RPAN_BROADCAST = "ERB";
private static final String IS_MUTE_STATE = "IMS";
+ @BindView(R.id.constraint_layout_exo_rpan_broadcast_playback_control_view)
+ ConstraintLayout constraintLayout;
@BindView(R.id.player_view_view_rpan_broadcast_fragment)
PlayerView playerView;
- @BindView(R.id.mute_exo_playback_control_view)
+ @BindView(R.id.recycler_view_exo_rpan_broadcast_playback_control_view)
+ RecyclerView recyclerView;
+ @BindView(R.id.mute_exo_rpan_broadcast_playback_control_view)
ImageButton muteButton;
- @BindView(R.id.hd_exo_playback_control_view)
+ @BindView(R.id.hd_exo_rpan_broadcast_playback_control_view)
ImageButton hdButton;
@Inject
@Named("default")
@@ -62,12 +83,14 @@ public class ViewRPANBroadcastFragment extends Fragment {
@Inject
CustomThemeWrapper mCustomThemeWrapper;
@Inject
- SimpleCache mSimpleCache;
+ Executor mExecutor;
private AppCompatActivity mActivity;
private RPANBroadcast rpanBroadcast;
private SimpleExoPlayer player;
private DefaultTrackSelector trackSelector;
private DataSource.Factory dataSourceFactory;
+ private Handler handler;
+ private RPANCommentStreamRecyclerViewAdapter adapter;
private boolean wasPlaying;
private boolean isMute = false;
@@ -90,6 +113,20 @@ public class ViewRPANBroadcastFragment extends Fragment {
rpanBroadcast = getArguments().getParcelable(EXTRA_RPAN_BROADCAST);
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT || getResources().getBoolean(R.bool.isTablet)) {
+ //Set player controller bottom margin in order to display it above the navbar
+ int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
+ //LinearLayout controllerLinearLayout = findViewById(R.id.linear_layout_exo_playback_control_view);
+ ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) constraintLayout.getLayoutParams();
+ params.bottomMargin = getResources().getDimensionPixelSize(resourceId);
+ } else {
+ //Set player controller right margin in order to display it above the navbar
+ int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
+ //LinearLayout controllerLinearLayout = findViewById(R.id.linear_layout_exo_playback_control_view);
+ ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) constraintLayout.getLayoutParams();
+ params.rightMargin = getResources().getDimensionPixelSize(resourceId);
+ }
+
playerView.setControllerVisibilityListener(visibility -> {
switch (visibility) {
case View.GONE:
@@ -186,6 +223,21 @@ public class ViewRPANBroadcastFragment extends Fragment {
}
});
+ adapter = new RPANCommentStreamRecyclerViewAdapter(mActivity);
+ recyclerView.setAdapter(adapter);
+
+ handler = new Handler();
+
+ Request request = new Request.Builder().url(rpanBroadcast.rpanPost.liveCommentsWebsocketUrl).build();
+ CommentStreamWebSocketListener listener = new CommentStreamWebSocketListener(this::parseComment);
+ OkHttpClient okHttpClient = new OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)
+ .readTimeout(30, TimeUnit.SECONDS)
+ .writeTimeout(30, TimeUnit.SECONDS)
+ .build();
+ WebSocket webSocket = okHttpClient.newWebSocket(request, listener);
+ okHttpClient.dispatcher().executorService().shutdown();
+
return rootView;
}
@@ -203,6 +255,26 @@ public class ViewRPANBroadcastFragment extends Fragment {
return false;
}
+ private void parseComment(String commentJson) {
+ mExecutor.execute(() -> {
+ try {
+ JSONObject commentObject = new JSONObject(commentJson);
+ if (commentObject.getString(JSONUtils.TYPE_KEY).equals("new_comment")) {
+ JSONObject payload = commentObject.getJSONObject(JSONUtils.PAYLOAD_KEY);
+ RPANComment rpanComment = new RPANComment(
+ payload.getString(JSONUtils.AUTHOR_KEY),
+ payload.getString(JSONUtils.AUTHOR_ICON_IMAGE),
+ payload.getString(JSONUtils.BODY_KEY),
+ payload.getLong(JSONUtils.CREATED_UTC_KEY));
+
+ handler.post(() -> adapter.addRPANComment(rpanComment));
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
@@ -237,4 +309,22 @@ public class ViewRPANBroadcastFragment extends Fragment {
super.onAttach(context);
mActivity = (AppCompatActivity) context;
}
+
+ private static class CommentStreamWebSocketListener extends WebSocketListener {
+ MessageReceivedListener messageReceivedListener;
+
+ CommentStreamWebSocketListener(MessageReceivedListener messageReceivedListener) {
+ this.messageReceivedListener = messageReceivedListener;
+ }
+
+ @Override
+ public void onMessage(@NonNull WebSocket webSocket, @NonNull String text) {
+ Log.i("asfasdf", "s " + text);
+ messageReceivedListener.onMessage(text);
+ }
+
+ interface MessageReceivedListener {
+ void onMessage(String text);
+ }
+ }
} \ No newline at end of file
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
index 579242a3..027d69dd 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
@@ -162,4 +162,6 @@ public class JSONUtils {
public static final String CHAT_DISABLED_KEY = "chat_disabled";
public static final String BROADCAST_TIME_KEY = "broadcast_time";
public static final String ESTIMATED_REMAINING_TIME_KEY = "estimated_remaining_time";
+ public static final String PAYLOAD_KEY = "payload";
+ public static final String AUTHOR_ICON_IMAGE = "author_icon_img";
}
diff --git a/app/src/main/res/layout/exo_rpan_broadcast_playback_control_view.xml b/app/src/main/res/layout/exo_rpan_broadcast_playback_control_view.xml
new file mode 100644
index 00000000..da7faea2
--- /dev/null
+++ b/app/src/main/res/layout/exo_rpan_broadcast_playback_control_view.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#44000000"
+ android:id="@+id/constraint_layout_exo_rpan_broadcast_playback_control_view"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <LinearLayout
+ android:id="@+id/control_linear_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:paddingTop="4dp"
+ android:orientation="horizontal"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <ImageButton
+ android:id="@+id/hd_exo_rpan_broadcast_playback_control_view"
+ android:src="@drawable/ic_video_quality_24dp"
+ style="@style/ExoMediaButton"
+ android:visibility="gone" />
+
+ <ImageButton android:id="@id/exo_rew"
+ style="@style/ExoMediaButton.Rewind" />
+
+ <ImageButton android:id="@id/exo_play"
+ style="@style/ExoMediaButton.Play"/>
+
+ <ImageButton android:id="@id/exo_pause"
+ style="@style/ExoMediaButton.Pause" />
+
+ <ImageButton android:id="@id/exo_ffwd"
+ style="@style/ExoMediaButton.FastForward" />
+
+ <ImageButton
+ android:id="@+id/mute_exo_rpan_broadcast_playback_control_view"
+ style="@style/ExoMediaButton"
+ android:visibility="gone" />
+
+ </LinearLayout>
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/recycler_view_exo_rpan_broadcast_playback_control_view"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:paddingTop="16dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ app:layout_constraintTop_toBottomOf="@id/control_linear_layout"
+ app:layout_constraintBottom_toTopOf="@id/time_bar_linear_layout"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
+
+ <LinearLayout
+ android:id="@+id/time_bar_linear_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:padding="16dp"
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <TextView android:id="@id/exo_position"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:paddingStart="0dp"
+ android:paddingEnd="4dp"
+ android:includeFontPadding="false"
+ android:textColor="#FFFFFF"
+ android:fontFamily="?attr/font_family" />
+
+ <com.google.android.exoplayer2.ui.DefaultTimeBar
+ android:id="@id/exo_progress"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="26dp"
+ app:bar_height="2dp"
+ app:scrubber_color="@color/colorAccent"
+ app:played_color="@color/colorAccent" />
+
+ <TextView android:id="@id/exo_duration"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="14sp"
+ android:textStyle="bold"
+ android:paddingStart="4dp"
+ android:paddingEnd="0dp"
+ android:includeFontPadding="false"
+ android:textColor="#FFFFFF"
+ android:fontFamily="?attr/font_family" />
+
+ </LinearLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_view_rpan_broadcast.xml b/app/src/main/res/layout/fragment_view_rpan_broadcast.xml
index bab40403..abab4f52 100644
--- a/app/src/main/res/layout/fragment_view_rpan_broadcast.xml
+++ b/app/src/main/res/layout/fragment_view_rpan_broadcast.xml
@@ -10,6 +10,6 @@
android:id="@+id/player_view_view_rpan_broadcast_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
- app:controller_layout_id="@layout/exo_playback_control_view" />
+ app:controller_layout_id="@layout/exo_rpan_broadcast_playback_control_view" />
</FrameLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/item_rpan_comment.xml b/app/src/main/res/layout/item_rpan_comment.xml
new file mode 100644
index 00000000..74766a90
--- /dev/null
+++ b/app/src/main/res/layout/item_rpan_comment.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:paddingBottom="8dp">
+
+ <ImageView
+ android:id="@+id/icon_image_view_item_rpan_comment"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="center_vertical" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="0dp"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/author_text_view_item_rpan_comment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textColor="@color/colorPrimary" />
+
+ <TextView
+ android:id="@+id/content_text_view_item_rpan_comment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="4dp"
+ android:textColor="#FFFFFF" />
+
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file