aboutsummaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--app/src/main/AndroidManifest.xml7
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java6
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java11
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/RPANBroadcast.java226
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java14
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java258
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/apis/Strapi.java12
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java225
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java1
-rw-r--r--app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java27
-rw-r--r--app/src/main/res/layout/activity_rpanactivity.xml33
-rw-r--r--app/src/main/res/layout/fragment_view_rpan_broadcast.xml22
-rw-r--r--app/src/main/res/values/strings.xml4
13 files changed, 835 insertions, 11 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a4275813..c492d535 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -32,7 +32,12 @@
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:replace="android:label">
- <activity android:name=".activities.MotionTestActivity"
+ <activity android:name=".activities.RPANActivity"
+ android:label="@string/rpan_activity_label"
+ android:parentActivityName=".activities.MainActivity"
+ android:theme="@style/AppTheme.NoActionBar" />
+ <activity
+ android:name=".activities.MotionTestActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".activities.LockScreenActivity"
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java
index 939858c7..fe68ecd4 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppComponent.java
@@ -31,6 +31,7 @@ import ml.docilealligator.infinityforreddit.activities.PostImageActivity;
import ml.docilealligator.infinityforreddit.activities.PostLinkActivity;
import ml.docilealligator.infinityforreddit.activities.PostTextActivity;
import ml.docilealligator.infinityforreddit.activities.PostVideoActivity;
+import ml.docilealligator.infinityforreddit.activities.RPANActivity;
import ml.docilealligator.infinityforreddit.activities.ReportActivity;
import ml.docilealligator.infinityforreddit.activities.RulesActivity;
import ml.docilealligator.infinityforreddit.activities.SearchActivity;
@@ -69,6 +70,7 @@ import ml.docilealligator.infinityforreddit.fragments.UserListingFragment;
import ml.docilealligator.infinityforreddit.fragments.ViewImgurImageFragment;
import ml.docilealligator.infinityforreddit.fragments.ViewImgurVideoFragment;
import ml.docilealligator.infinityforreddit.fragments.ViewPostDetailFragment;
+import ml.docilealligator.infinityforreddit.fragments.ViewRPANBroadcastFragment;
import ml.docilealligator.infinityforreddit.fragments.ViewRedditGalleryImageOrGifFragment;
import ml.docilealligator.infinityforreddit.fragments.ViewRedditGalleryVideoFragment;
import ml.docilealligator.infinityforreddit.services.DownloadMediaService;
@@ -269,4 +271,8 @@ public interface AppComponent {
void inject(LockScreenActivity lockScreenActivity);
void inject(MaterialYouService materialYouService);
+
+ void inject(RPANActivity rpanActivity);
+
+ void inject(ViewRPANBroadcastFragment viewRPANBroadcastFragment);
}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java
index 18e43156..b539fc89 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/AppModule.java
@@ -153,6 +153,17 @@ class AppModule {
}
@Provides
+ @Named("strapi")
+ @Singleton
+ Retrofit providestrapiRetrofit(OkHttpClient okHttpClient) {
+ return new Retrofit.Builder()
+ .baseUrl(APIUtils.STRAPI_BASE_URI)
+ .client(okHttpClient)
+ .addConverterFactory(ScalarsConverterFactory.create())
+ .build();
+ }
+
+ @Provides
@Singleton
OkHttpClient provideOkHttpClient(@Named("no_oauth") Retrofit retrofit, RedditDataRoomDatabase accountRoomDatabase,
@Named("current_account") SharedPreferences currentAccountSharedPreferences) {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/RPANBroadcast.java b/app/src/main/java/ml/docilealligator/infinityforreddit/RPANBroadcast.java
new file mode 100644
index 00000000..43b8ef55
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/RPANBroadcast.java
@@ -0,0 +1,226 @@
+package ml.docilealligator.infinityforreddit;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class RPANBroadcast implements Parcelable {
+
+ public int upvotes;
+ public int downvotes;
+ public int uniqueWatchers;
+ public int continuousWatchers;
+ public int totalContinuousWatchers;
+ public boolean chatDisabled;
+ public double broadcastTime;
+ public double estimatedRemainingTime;
+
+ public RPANPost rpanPost;
+ public RPANStream rpanStream;
+
+ public RPANBroadcast(int upvotes, int downvotes, int uniqueWatchers, int continuousWatchers,
+ int totalContinuousWatchers, boolean chatDisabled, double broadcastTime,
+ double estimatedRemainingTime, RPANPost rpanPost, RPANStream rpanStream) {
+ this.upvotes = upvotes;
+ this.downvotes = downvotes;
+ this.uniqueWatchers = uniqueWatchers;
+ this.continuousWatchers = continuousWatchers;
+ this.totalContinuousWatchers = totalContinuousWatchers;
+ this.chatDisabled = chatDisabled;
+ this.broadcastTime = broadcastTime;
+ this.estimatedRemainingTime = estimatedRemainingTime;
+ this.rpanPost = rpanPost;
+ this.rpanStream = rpanStream;
+ }
+
+ protected RPANBroadcast(Parcel in) {
+ upvotes = in.readInt();
+ downvotes = in.readInt();
+ uniqueWatchers = in.readInt();
+ continuousWatchers = in.readInt();
+ totalContinuousWatchers = in.readInt();
+ chatDisabled = in.readByte() != 0;
+ broadcastTime = in.readDouble();
+ estimatedRemainingTime = in.readDouble();
+ rpanPost = in.readParcelable(RPANPost.class.getClassLoader());
+ rpanStream = in.readParcelable(RPANStream.class.getClassLoader());
+ }
+
+ public static final Creator<RPANBroadcast> CREATOR = new Creator<RPANBroadcast>() {
+ @Override
+ public RPANBroadcast createFromParcel(Parcel in) {
+ return new RPANBroadcast(in);
+ }
+
+ @Override
+ public RPANBroadcast[] newArray(int size) {
+ return new RPANBroadcast[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeInt(upvotes);
+ parcel.writeInt(downvotes);
+ parcel.writeInt(uniqueWatchers);
+ parcel.writeInt(continuousWatchers);
+ parcel.writeInt(totalContinuousWatchers);
+ parcel.writeByte((byte) (chatDisabled ? 1 : 0));
+ parcel.writeDouble(broadcastTime);
+ parcel.writeDouble(estimatedRemainingTime);
+ parcel.writeParcelable(rpanPost, i);
+ parcel.writeParcelable(rpanStream, i);
+ }
+
+ public static class RPANPost implements Parcelable{
+ public String title;
+ public String subredditName;
+ public String subredditIconUrl;
+ public String username;
+ public int postScore;
+ public String voteState;
+ public double upvoteRatio;
+ public String postPermalink;
+ public boolean isNsfw;
+ public boolean isLocked;
+ public boolean isArchived;
+ public boolean isSpoiler;
+ public String suggestedCommentSort;
+ public String liveCommentsWebsocketUrl;
+
+ public RPANPost(String title, String subredditName, String subredditIconUrl, String username,
+ int postScore, String voteState, double upvoteRatio, String postPermalink, String rpanUrl,
+ boolean isNsfw, boolean isLocked, boolean isArchived, boolean isSpoiler,
+ String suggestedCommentSort, String liveCommentsWebsocketUrl) {
+ this.title = title;
+ this.subredditName = subredditName;
+ this.subredditIconUrl = subredditIconUrl;
+ this.username = username;
+ this.postScore = postScore;
+ this.voteState = voteState;
+ this.upvoteRatio = upvoteRatio;
+ this.postPermalink = postPermalink;
+ this.isNsfw = isNsfw;
+ this.isLocked = isLocked;
+ this.isArchived = isArchived;
+ this.isSpoiler = isSpoiler;
+ this.suggestedCommentSort = suggestedCommentSort;
+ this.liveCommentsWebsocketUrl = liveCommentsWebsocketUrl;
+ }
+
+ protected RPANPost(Parcel in) {
+ title = in.readString();
+ subredditName = in.readString();
+ subredditIconUrl = in.readString();
+ username = in.readString();
+ postScore = in.readInt();
+ voteState = in.readString();
+ upvoteRatio = in.readDouble();
+ postPermalink = in.readString();
+ isNsfw = in.readByte() != 0;
+ isLocked = in.readByte() != 0;
+ isArchived = in.readByte() != 0;
+ isSpoiler = in.readByte() != 0;
+ suggestedCommentSort = in.readString();
+ liveCommentsWebsocketUrl = in.readString();
+ }
+
+ public static final Creator<RPANPost> CREATOR = new Creator<RPANPost>() {
+ @Override
+ public RPANPost createFromParcel(Parcel in) {
+ return new RPANPost(in);
+ }
+
+ @Override
+ public RPANPost[] newArray(int size) {
+ return new RPANPost[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeString(title);
+ parcel.writeString(subredditName);
+ parcel.writeString(subredditIconUrl);
+ parcel.writeString(username);
+ parcel.writeInt(postScore);
+ parcel.writeString(voteState);
+ parcel.writeDouble(upvoteRatio);
+ parcel.writeString(postPermalink);
+ parcel.writeByte((byte) (isNsfw ? 1 : 0));
+ parcel.writeByte((byte) (isLocked ? 1 : 0));
+ parcel.writeByte((byte) (isArchived ? 1 : 0));
+ parcel.writeByte((byte) (isSpoiler ? 1 : 0));
+ parcel.writeString(suggestedCommentSort);
+ parcel.writeString(liveCommentsWebsocketUrl);
+ }
+ }
+
+ public static class RPANStream implements Parcelable {
+ public String streamId;
+ public String hlsUrl;
+ public String thumbnail;
+ public int width;
+ public int height;
+ public long publishAt;
+ public String state;
+
+ public RPANStream(String streamId, String hlsUrl, String thumbnail, int width, int height, long publishAt,
+ String state) {
+ this.streamId = streamId;
+ this.hlsUrl = hlsUrl;
+ this.thumbnail = thumbnail;
+ this.width = width;
+ this.height = height;
+ this.publishAt = publishAt;
+ this.state = state;
+ }
+
+ protected RPANStream(Parcel in) {
+ streamId = in.readString();
+ hlsUrl = in.readString();
+ thumbnail = in.readString();
+ width = in.readInt();
+ height = in.readInt();
+ publishAt = in.readLong();
+ state = in.readString();
+ }
+
+ public static final Creator<RPANStream> CREATOR = new Creator<RPANStream>() {
+ @Override
+ public RPANStream createFromParcel(Parcel in) {
+ return new RPANStream(in);
+ }
+
+ @Override
+ public RPANStream[] newArray(int size) {
+ return new RPANStream[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeString(streamId);
+ parcel.writeString(hlsUrl);
+ parcel.writeString(thumbnail);
+ parcel.writeInt(width);
+ parcel.writeInt(height);
+ parcel.writeLong(publishAt);
+ parcel.writeString(state);
+ }
+ }
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java
index 6549c44e..4a2c945a 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/MainActivity.java
@@ -9,8 +9,6 @@ import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.text.Editable;
-import android.text.TextWatcher;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
@@ -83,8 +81,6 @@ import ml.docilealligator.infinityforreddit.SortType;
import ml.docilealligator.infinityforreddit.SortTypeSelectionCallback;
import ml.docilealligator.infinityforreddit.account.AccountViewModel;
import ml.docilealligator.infinityforreddit.adapters.NavigationDrawerRecyclerViewAdapter;
-import ml.docilealligator.infinityforreddit.adapters.SubredditAutocompleteRecyclerViewAdapter;
-import ml.docilealligator.infinityforreddit.apis.RedditAPI;
import ml.docilealligator.infinityforreddit.asynctasks.InsertSubscribedThings;
import ml.docilealligator.infinityforreddit.asynctasks.SwitchAccount;
import ml.docilealligator.infinityforreddit.asynctasks.SwitchToAnonymousMode;
@@ -110,20 +106,16 @@ import ml.docilealligator.infinityforreddit.multireddit.MultiRedditViewModel;
import ml.docilealligator.infinityforreddit.post.Post;
import ml.docilealligator.infinityforreddit.post.PostDataSource;
import ml.docilealligator.infinityforreddit.readpost.InsertReadPost;
-import ml.docilealligator.infinityforreddit.subreddit.ParseSubredditData;
import ml.docilealligator.infinityforreddit.subreddit.SubredditData;
import ml.docilealligator.infinityforreddit.subscribedsubreddit.SubscribedSubredditData;
import ml.docilealligator.infinityforreddit.subscribedsubreddit.SubscribedSubredditViewModel;
import ml.docilealligator.infinityforreddit.subscribeduser.SubscribedUserData;
import ml.docilealligator.infinityforreddit.user.FetchUserData;
import ml.docilealligator.infinityforreddit.user.UserData;
-import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.CustomThemeSharedPreferencesUtils;
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
import ml.docilealligator.infinityforreddit.utils.Utils;
import retrofit2.Call;
-import retrofit2.Callback;
-import retrofit2.Response;
import retrofit2.Retrofit;
import static androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO;
@@ -1381,7 +1373,7 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
}
private void goToSubreddit() {
- View rootView = getLayoutInflater().inflate(R.layout.dialog_go_to_thing_edit_text, coordinatorLayout, false);
+ /*View rootView = getLayoutInflater().inflate(R.layout.dialog_go_to_thing_edit_text, coordinatorLayout, false);
TextInputEditText thingEditText = rootView.findViewById(R.id.text_input_edit_text_go_to_thing_edit_text);
RecyclerView recyclerView = rootView.findViewById(R.id.recycler_view_go_to_thing_edit_text);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -1475,7 +1467,9 @@ public class MainActivity extends BaseActivity implements SortTypeSelectionCallb
imm.hideSoftInputFromWindow(thingEditText.getWindowToken(), 0);
}
})
- .show();
+ .show();*/
+ Intent intent = new Intent(this, RPANActivity.class);
+ startActivity(intent);
}
private void goToUser() {
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java
new file mode 100644
index 00000000..22fa13db
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/activities/RPANActivity.java
@@ -0,0 +1,258 @@
+package ml.docilealligator.infinityforreddit.activities;
+
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.Toolbar;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+import androidx.viewpager2.widget.ViewPager2;
+
+import com.google.android.material.appbar.AppBarLayout;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import ml.docilealligator.infinityforreddit.Infinity;
+import ml.docilealligator.infinityforreddit.R;
+import ml.docilealligator.infinityforreddit.RPANBroadcast;
+import ml.docilealligator.infinityforreddit.apis.Strapi;
+import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
+import ml.docilealligator.infinityforreddit.fragments.ViewRPANBroadcastFragment;
+import ml.docilealligator.infinityforreddit.utils.APIUtils;
+import ml.docilealligator.infinityforreddit.utils.JSONUtils;
+import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+
+public class RPANActivity extends BaseActivity {
+
+ @BindView(R.id.coordinator_layout_rpan_activity)
+ CoordinatorLayout coordinatorLayout;
+ @BindView(R.id.appbar_layout_rpan_activity)
+ AppBarLayout appBarLayout;
+ @BindView(R.id.toolbar_rpan_activity)
+ Toolbar toolbar;
+ @BindView(R.id.view_pager_2_rpan_activity)
+ ViewPager2 viewPager2;
+ @Inject
+ @Named("strapi")
+ Retrofit strapiRetrofit;
+ @Inject
+ @Named("default")
+ SharedPreferences mSharedPreferences;
+ @Inject
+ @Named("current_account")
+ SharedPreferences mCurrentAccountSharedPreferences;
+ @Inject
+ CustomThemeWrapper mCustomThemeWrapper;
+ @Inject
+ Executor mExecutor;
+ private String mAccessToken;
+ private String mAccountName;
+ private ArrayList<RPANBroadcast> rpanBroadcasts;
+ private String nextCursor;
+ private SectionsPagerAdapter sectionsPagerAdapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ ((Infinity) getApplication()).getAppComponent().inject(this);
+
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_rpanactivity);
+
+ ButterKnife.bind(this);
+
+ applyCustomTheme();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ Window window = getWindow();
+
+ if (isChangeStatusBarIconColor()) {
+ addOnOffsetChangedListener(appBarLayout);
+ }
+
+ if (isImmersiveInterface()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+ coordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+ } else {
+ window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
+ }
+ adjustToolbar(toolbar);
+ }
+ }
+
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+ mAccessToken = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCESS_TOKEN, null);
+ mAccountName = mCurrentAccountSharedPreferences.getString(SharedPreferencesUtils.ACCOUNT_NAME, null);
+
+ loadRPANVideos();
+ }
+
+ private void loadRPANVideos() {
+ strapiRetrofit.create(Strapi.class).getAllBroadcasts(APIUtils.getOAuthHeader(mAccessToken)).enqueue(new Callback<String>() {
+ @Override
+ public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
+ if (response.isSuccessful()) {
+ parseRPANBroadcasts(response.body());
+ } else {
+ Toast.makeText(RPANActivity.this,
+ R.string.load_rpan_broadcasts_failed, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
+ Toast.makeText(RPANActivity.this,
+ R.string.load_rpan_broadcasts_failed, Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ private void parseRPANBroadcasts(String response) {
+ Handler handler = new Handler();
+ mExecutor.execute(() -> {
+ try {
+ ArrayList<RPANBroadcast> rpanBroadcasts = new ArrayList<>();
+ JSONObject responseObject = new JSONObject(response);
+ String nextCursor = responseObject.getString(JSONUtils.NEXT_CURSOR_KEY);
+
+ JSONArray dataArray = responseObject.getJSONArray(JSONUtils.DATA_KEY);
+ for (int i = 0; i < dataArray.length(); i++) {
+ JSONObject singleData = dataArray.getJSONObject(i);
+ JSONObject rpanPostObject = singleData.getJSONObject(JSONUtils.POST_KEY);
+ RPANBroadcast.RPANPost rpanPost = new RPANBroadcast.RPANPost(
+ rpanPostObject.getString(JSONUtils.TITLE_KEY),
+ rpanPostObject.getJSONObject(JSONUtils.SUBREDDIT_KEY).getString(JSONUtils.NAME_KEY),
+ rpanPostObject.getJSONObject(JSONUtils.SUBREDDIT_KEY).getJSONObject(JSONUtils.STYLES_KEY).getString(JSONUtils.ICON_KEY),
+ rpanPostObject.getJSONObject(JSONUtils.AUTHOR_INFO_KEY).getString(JSONUtils.NAME_KEY),
+ rpanPostObject.getInt(JSONUtils.SCORE_KEY),
+ rpanPostObject.getString(JSONUtils.VOTE_STATE_KEY),
+ rpanPostObject.getDouble(JSONUtils.UPVOTE_RATIO_CAMEL_CASE_KEY),
+ rpanPostObject.getString(JSONUtils.PERMALINK_KEY),
+ rpanPostObject.getJSONObject(JSONUtils.OUTBOUND_LINK_KEY).getString(JSONUtils.URL_KEY),
+ rpanPostObject.getBoolean(JSONUtils.IS_NSFW_KEY),
+ rpanPostObject.getBoolean(JSONUtils.IS_LOCKED_KEY),
+ rpanPostObject.getBoolean(JSONUtils.IS_ARCHIVED_KEY),
+ rpanPostObject.getBoolean(JSONUtils.IS_SPOILER),
+ rpanPostObject.getString(JSONUtils.SUGGESTED_COMMENT_SORT_CAMEL_CASE_KEY),
+ rpanPostObject.getString(JSONUtils.LIVE_COMMENTS_WEBSOCKET_KEY)
+ );
+
+ JSONObject rpanStreamObject = singleData.getJSONObject(JSONUtils.STREAM_KEY);
+ RPANBroadcast.RPANStream rpanStream = new RPANBroadcast.RPANStream(
+ rpanStreamObject.getString(JSONUtils.STREAM_ID_KEY),
+ rpanStreamObject.getString(JSONUtils.HLS_URL_KEY),
+ rpanStreamObject.getString(JSONUtils.THUMBNAIL_KEY),
+ rpanStreamObject.getInt(JSONUtils.WIDTH_KEY),
+ rpanStreamObject.getInt(JSONUtils.HEIGHT_KEY),
+ rpanStreamObject.getLong(JSONUtils.PUBLISH_AT_KEY),
+ rpanStreamObject.getString(JSONUtils.STATE_KEY)
+ );
+
+ rpanBroadcasts.add(new RPANBroadcast(
+ singleData.getInt(JSONUtils.UPVOTES_KEY),
+ singleData.getInt(JSONUtils.DOWNVOTES_KEY),
+ singleData.getInt(JSONUtils.UNIQUE_WATCHERS_KEY),
+ singleData.getInt(JSONUtils.CONTINUOUS_WATCHERS_KEY),
+ singleData.getInt(JSONUtils.TOTAL_CONTINUOUS_WATCHERS_KEY),
+ singleData.getBoolean(JSONUtils.CHAT_DISABLED_KEY),
+ singleData.getDouble(JSONUtils.BROADCAST_TIME_KEY),
+ singleData.getDouble(JSONUtils.ESTIMATED_REMAINING_TIME_KEY),
+ rpanPost,
+ rpanStream
+ ));
+ }
+
+ handler.post(() -> {
+ RPANActivity.this.rpanBroadcasts = rpanBroadcasts;
+ RPANActivity.this.nextCursor = nextCursor;
+
+ initializeViewPager();
+ });
+ } catch (JSONException e) {
+ e.printStackTrace();
+ handler.post(() -> Toast.makeText(RPANActivity.this,
+ R.string.parse_rpan_broadcasts_failed, Toast.LENGTH_SHORT).show());
+ }
+ });
+ }
+
+ private void initializeViewPager() {
+ sectionsPagerAdapter = new SectionsPagerAdapter(this);
+ viewPager2.setAdapter(sectionsPagerAdapter);
+ viewPager2.setOffscreenPageLimit(3);
+ viewPager2.setUserInputEnabled(!mSharedPreferences.getBoolean(SharedPreferencesUtils.DISABLE_SWIPING_BETWEEN_TABS, false));
+ fixViewPager2Sensitivity(viewPager2);
+ }
+
+ @Override
+ protected SharedPreferences getDefaultSharedPreferences() {
+ return mSharedPreferences;
+ }
+
+ @Override
+ protected CustomThemeWrapper getCustomThemeWrapper() {
+ return mCustomThemeWrapper;
+ }
+
+ @Override
+ protected void applyCustomTheme() {
+
+ }
+
+ private class SectionsPagerAdapter extends FragmentStateAdapter {
+
+ public SectionsPagerAdapter(FragmentActivity fa) {
+ super(fa);
+ }
+
+ @NonNull
+ @Override
+ public Fragment createFragment(int position) {
+ ViewRPANBroadcastFragment fragment = new ViewRPANBroadcastFragment();
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(ViewRPANBroadcastFragment.EXTRA_RPAN_BROADCAST, rpanBroadcasts.get(position));
+ fragment.setArguments(bundle);
+ return fragment;
+ }
+
+ @Nullable
+ private Fragment getCurrentFragment() {
+ if (viewPager2 == null || getSupportFragmentManager() == null) {
+ return null;
+ }
+ return getSupportFragmentManager().findFragmentByTag("f" + viewPager2.getCurrentItem());
+ }
+
+ @Override
+ public int getItemCount() {
+ return rpanBroadcasts == null ? 0 : rpanBroadcasts.size();
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/apis/Strapi.java b/app/src/main/java/ml/docilealligator/infinityforreddit/apis/Strapi.java
new file mode 100644
index 00000000..2c8f4797
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/apis/Strapi.java
@@ -0,0 +1,12 @@
+package ml.docilealligator.infinityforreddit.apis;
+
+import java.util.Map;
+
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.HeaderMap;
+
+public interface Strapi {
+ @GET("/broadcasts")
+ Call<String> getAllBroadcasts(@HeaderMap Map<String ,String> headers);
+}
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java
new file mode 100644
index 00000000..3be8e7de
--- /dev/null
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/fragments/ViewRPANBroadcastFragment.java
@@ -0,0 +1,225 @@
+package ml.docilealligator.infinityforreddit.fragments;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+
+import com.google.android.exoplayer2.ExoPlaybackException;
+import com.google.android.exoplayer2.ExoPlayerFactory;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.SimpleExoPlayer;
+import com.google.android.exoplayer2.source.BehindLiveWindowException;
+import com.google.android.exoplayer2.source.TrackGroupArray;
+import com.google.android.exoplayer2.source.hls.HlsMediaSource;
+import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
+import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
+import com.google.android.exoplayer2.trackselection.TrackSelection;
+import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
+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 javax.inject.Inject;
+import javax.inject.Named;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import ml.docilealligator.infinityforreddit.Infinity;
+import ml.docilealligator.infinityforreddit.R;
+import ml.docilealligator.infinityforreddit.RPANBroadcast;
+import ml.docilealligator.infinityforreddit.customtheme.CustomThemeWrapper;
+import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
+
+public class ViewRPANBroadcastFragment extends Fragment {
+
+ public static final String EXTRA_RPAN_BROADCAST = "ERB";
+ private static final String IS_MUTE_STATE = "IMS";
+
+ @BindView(R.id.player_view_view_rpan_broadcast_fragment)
+ PlayerView playerView;
+ @BindView(R.id.progress_bar_view_rpan_broadcast_fragment)
+ ProgressBar progressBar;
+ @BindView(R.id.mute_exo_playback_control_view)
+ ImageButton muteButton;
+ @BindView(R.id.hd_exo_playback_control_view)
+ ImageButton hdButton;
+ @Inject
+ @Named("default")
+ SharedPreferences mSharedPreferences;
+ @Inject
+ @Named("current_account")
+ SharedPreferences mCurrentAccountSharedPreferences;
+ @Inject
+ CustomThemeWrapper mCustomThemeWrapper;
+ @Inject
+ SimpleCache mSimpleCache;
+ private AppCompatActivity mActivity;
+ private RPANBroadcast rpanBroadcast;
+ private SimpleExoPlayer player;
+ private DefaultTrackSelector trackSelector;
+ private DataSource.Factory dataSourceFactory;
+
+ private boolean wasPlaying;
+ private boolean isMute = false;
+ private long resumePosition = -1;
+ private boolean isDataSavingMode;
+
+ public ViewRPANBroadcastFragment() {
+ // Required empty public constructor
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // Inflate the layout for this fragment
+ View rootView = inflater.inflate(R.layout.fragment_view_rpan_broadcast, container, false);
+
+ ((Infinity) mActivity.getApplication()).getAppComponent().inject(this);
+
+ ButterKnife.bind(this, rootView);
+
+ rpanBroadcast = getArguments().getParcelable(EXTRA_RPAN_BROADCAST);
+
+ TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory();
+ trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
+ player = ExoPlayerFactory.newSimpleInstance(mActivity, trackSelector);
+ playerView.setPlayer(player);
+
+ dataSourceFactory = new DefaultHttpDataSourceFactory(Util.getUserAgent(mActivity, "Infinity"));
+ // Prepare the player with the source.
+ player.prepare(new HlsMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(rpanBroadcast.rpanStream.hlsUrl)));
+ player.setRepeatMode(Player.REPEAT_MODE_ALL);
+ if (resumePosition > 0) {
+ player.seekTo(resumePosition);
+ }
+ player.setPlayWhenReady(true);
+ wasPlaying = true;
+
+ boolean muteVideo = mSharedPreferences.getBoolean(SharedPreferencesUtils.MUTE_VIDEO, false) ||
+ (mSharedPreferences.getBoolean(SharedPreferencesUtils.MUTE_NSFW_VIDEO, false) && rpanBroadcast.rpanPost.isNsfw);
+
+ if (savedInstanceState != null) {
+ isMute = savedInstanceState.getBoolean(IS_MUTE_STATE);
+ if (isMute) {
+ player.setVolume(0f);
+ muteButton.setImageResource(R.drawable.ic_mute_24dp);
+ } else {
+ player.setVolume(1f);
+ muteButton.setImageResource(R.drawable.ic_unmute_24dp);
+ }
+ } else if (muteVideo) {
+ isMute = true;
+ player.setVolume(0f);
+ muteButton.setImageResource(R.drawable.ic_mute_24dp);
+ } else {
+ muteButton.setImageResource(R.drawable.ic_unmute_24dp);
+ }
+
+ player.addListener(new Player.EventListener() {
+ @Override
+ public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
+ if (!trackGroups.isEmpty()) {
+ if (isDataSavingMode) {
+ trackSelector.setParameters(
+ trackSelector.buildUponParameters()
+ .setMaxVideoSize(720, 720));
+ }
+
+ hdButton.setVisibility(View.VISIBLE);
+ hdButton.setOnClickListener(view -> {
+ TrackSelectionDialogBuilder build = new TrackSelectionDialogBuilder(mActivity,
+ getString(R.string.select_video_quality), trackSelector, 0);
+ build.setShowDisableOption(true);
+ build.setAllowAdaptiveSelections(false);
+ build.build().show();
+ });
+
+ for (int i = 0; i < trackGroups.length; i++) {
+ String mimeType = trackGroups.get(i).getFormat(0).sampleMimeType;
+ if (mimeType != null && mimeType.contains("audio")) {
+ muteButton.setVisibility(View.VISIBLE);
+ muteButton.setOnClickListener(view -> {
+ if (isMute) {
+ isMute = false;
+ player.setVolume(1f);
+ muteButton.setImageResource(R.drawable.ic_unmute_24dp);
+ } else {
+ isMute = true;
+ player.setVolume(0f);
+ muteButton.setImageResource(R.drawable.ic_mute_24dp);
+ }
+ });
+ break;
+ }
+ }
+ } else {
+ muteButton.setVisibility(View.GONE);
+ }
+ }
+ });
+
+ return rootView;
+ }
+
+ private boolean isBehindLiveWindow(ExoPlaybackException e) {
+ if (e.type != ExoPlaybackException.TYPE_SOURCE) {
+ return false;
+ }
+ Throwable cause = e.getSourceException();
+ while (cause != null) {
+ if (cause instanceof BehindLiveWindowException) {
+ return true;
+ }
+ cause = cause.getCause();
+ }
+ return false;
+ }
+
+ @Override
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(IS_MUTE_STATE, isMute);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ if (wasPlaying) {
+ player.setPlayWhenReady(true);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ wasPlaying = player.getPlayWhenReady();
+ player.setPlayWhenReady(false);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ player.seekToDefaultPosition();
+ player.stop(true);
+ player.release();
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ mActivity = (AppCompatActivity) context;
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java
index fb49b49e..5ad14398 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/APIUtils.java
@@ -22,6 +22,7 @@ public class APIUtils {
public static final String REDGIFS_API_BASE_URI = "https://api.redgifs.com/v1/gfycats/";
public static final String IMGUR_API_BASE_URI = "https://api.imgur.com/3/";
public static final String PUSHSHIFT_API_BASE_URI = "https://api.pushshift.io/";
+ public static final String STRAPI_BASE_URI = "https://strapi.reddit.com";
public static final String CLIENT_ID_KEY = "client_id";
public static final String CLIENT_ID = "NOe2iKrPPzwscA";
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 8ba23bf4..579242a3 100644
--- a/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
+++ b/app/src/main/java/ml/docilealligator/infinityforreddit/utils/JSONUtils.java
@@ -135,4 +135,31 @@ public class JSONUtils {
public static final String WEBM_URL_KEY = "webmUrl";
public static final String UPVOTE_RATIO_KEY = "upvote_ratio";
public static final String INBOX_COUNT_KEY = "inbox_count";
+ public static final String NEXT_CURSOR_KEY = "next_cursor";
+ public static final String POST_KEY = "post";
+ public static final String STYLES_KEY = "styles";
+ public static final String AUTHOR_INFO_KEY= "authorInfo";
+ public static final String VOTE_STATE_KEY = "voteState";
+ public static final String UPVOTE_RATIO_CAMEL_CASE_KEY = "upvoteRatio";
+ public static final String OUTBOUND_LINK_KEY = "outboundLink";
+ public static final String IS_NSFW_KEY = "isNsfw";
+ public static final String IS_LOCKED_KEY = "isLocked";
+ public static final String IS_ARCHIVED_KEY = "isArchived";
+ public static final String IS_SPOILER = "isSpoiler";
+ public static final String SUGGESTED_COMMENT_SORT_CAMEL_CASE_KEY = "suggestedCommentSort";
+ public static final String LIVE_COMMENTS_WEBSOCKET_KEY = "liveCommentsWebsocket";
+ public static final String ICON_KEY = "icon";
+ public static final String STREAM_KEY = "stream";
+ public static final String STREAM_ID_KEY = "stream_id";
+ public static final String THUMBNAIL_KEY = "thumbnail";
+ public static final String PUBLISH_AT_KEY = "publish_at";
+ public static final String STATE_KEY = "state";
+ public static final String UPVOTES_KEY = "upvotes";
+ public static final String DOWNVOTES_KEY = "downvotes";
+ public static final String UNIQUE_WATCHERS_KEY = "unique_watchers";
+ public static final String CONTINUOUS_WATCHERS_KEY = "continuous_watchers";
+ public static final String TOTAL_CONTINUOUS_WATCHERS_KEY = "total_continuous_watchers";
+ 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";
}
diff --git a/app/src/main/res/layout/activity_rpanactivity.xml b/app/src/main/res/layout/activity_rpanactivity.xml
new file mode 100644
index 00000000..8d1c85fb
--- /dev/null
+++ b/app/src/main/res/layout/activity_rpanactivity.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#000000"
+ android:id="@+id/coordinator_layout_rpan_activity"
+ tools:context=".activities.RPANActivity">
+
+ <com.google.android.material.appbar.AppBarLayout
+ android:id="@+id/appbar_layout_rpan_activity"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="@style/AppTheme.AppBarOverlay">
+
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar_rpan_activity"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent"
+ android:minHeight="?attr/actionBarSize"
+ app:popupTheme="@style/AppTheme.PopupOverlay"
+ app:navigationIcon="?attr/homeAsUpIndicator" />
+
+ </com.google.android.material.appbar.AppBarLayout>
+
+ <androidx.viewpager2.widget.ViewPager2
+ android:id="@+id/view_pager_2_rpan_activity"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</androidx.coordinatorlayout.widget.CoordinatorLayout> \ 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
new file mode 100644
index 00000000..fdfe62c6
--- /dev/null
+++ b/app/src/main/res/layout/fragment_view_rpan_broadcast.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ tools:context=".fragments.ViewRPANBroadcastFragment">
+
+ <com.google.android.exoplayer2.ui.PlayerView
+ 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" />
+
+ <ProgressBar
+ android:id="@+id/progress_bar_view_rpan_broadcast_fragment"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:visibility="gone" />
+
+</FrameLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 79870453..1d6753ba 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -39,6 +39,7 @@
<string name="post_filter_preference_activity_label">Post Filter</string>
<string name="search_users_result_activity_label">Users</string>
<string name="multireddit_selection_activity_label">Select a Multireddit</string>
+ <string name="rpan_activity_label">RPAN</string>
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
@@ -1126,4 +1127,7 @@
<string name="get_image_bitmap_failed">Unable to get the bitmap of the image</string>
<string name="upload_image_failed">Unable to upload the image</string>
+ <string name="load_rpan_broadcasts_failed">Cannot load RPAN broadcasts</string>
+ <string name="parse_rpan_broadcasts_failed">Cannot parse RPAN broadcasts</string>
+
</resources>