Skip to content

Commit c15f117

Browse files
Add an option to download media in PostOptionsBottomSheetFragment.
1 parent 341f1b3 commit c15f117

File tree

11 files changed

+293
-43
lines changed

11 files changed

+293
-43
lines changed

app/src/main/java/ml/docilealligator/infinityforreddit/VideoLinkFetcher.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import androidx.annotation.NonNull;
88
import androidx.annotation.Nullable;
99
import androidx.annotation.OptIn;
10+
import androidx.annotation.WorkerThread;
1011
import androidx.media3.common.util.UnstableApi;
1112

1213
import org.apache.commons.io.FilenameUtils;
@@ -24,6 +25,7 @@
2425
import ml.docilealligator.infinityforreddit.post.FetchStreamableVideo;
2526
import ml.docilealligator.infinityforreddit.post.Post;
2627
import ml.docilealligator.infinityforreddit.thing.FetchRedgifsVideoLinks;
28+
import ml.docilealligator.infinityforreddit.thing.StreamableVideo;
2729
import retrofit2.Call;
2830
import retrofit2.Callback;
2931
import retrofit2.Response;
@@ -51,6 +53,22 @@ public static void fetchVideoLink(Executor executor, Handler handler, Retrofit r
5153
}
5254
}
5355

56+
@WorkerThread
57+
@Nullable
58+
public static String fetchVideoLinkSync(Retrofit redgifsRetrofit, Provider<StreamableAPI> streamableApiProvider,
59+
SharedPreferences currentAccountSharedPreferences, int videoType,
60+
@Nullable String redgifsId, @Nullable String shortCode) {
61+
if (videoType == ViewVideoActivity.VIDEO_TYPE_STREAMABLE) {
62+
StreamableVideo streamableVideo = FetchStreamableVideo.fetchStreamableVideoSync(streamableApiProvider, shortCode);
63+
return streamableVideo == null ? null : (streamableVideo.mp4 == null ? null : streamableVideo.mp4.url);
64+
} else if (videoType == ViewVideoActivity.VIDEO_TYPE_REDGIFS) {
65+
return FetchRedgifsVideoLinks.fetchRedgifsVideoLinkSync(redgifsRetrofit,
66+
currentAccountSharedPreferences, redgifsId);
67+
}
68+
69+
return null;
70+
}
71+
5472
public static void loadVReddItVideo(Executor executor, Handler handler, Retrofit retrofit, Retrofit mVReddItRetrofit,
5573
Retrofit redgifsRetrofit, Provider<StreamableAPI> streamableApiProvider,
5674
SharedPreferences currentAccountSharedPreferences,
@@ -87,7 +105,7 @@ public void fetchPostSuccess(Post post) {
87105
FetchStreamableVideo.fetchStreamableVideo(executor, handler, streamableApiProvider, shortCode, fetchVideoLinkListener);
88106
} else if (post.isImgur()) {
89107
String videoDownloadUrl = post.getVideoDownloadUrl();
90-
String videoFileName = "imgur-" + FilenameUtils.getName(videoDownloadUrl);
108+
String videoFileName = "Imgur-" + FilenameUtils.getName(videoDownloadUrl);
91109
fetchVideoLinkListener.onFetchImgurVideoLinkSuccess(post.getVideoUrl(), post.getVideoDownloadUrl(), videoFileName);
92110
} else {
93111
if (post.getVideoUrl() != null) {

app/src/main/java/ml/docilealligator/infinityforreddit/activities/ViewVideoActivity.java

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -475,25 +475,22 @@ public void onIdle(@NonNull ZoomEngine zoomEngine) {
475475
} else {
476476
PlayerView videoPlayerView = findViewById(R.id.player_view_view_video_activity);
477477
videoPlayerView.setPlayer(player);
478-
videoPlayerView.setControllerVisibilityListener(new PlayerView.ControllerVisibilityListener() {
479-
@Override
480-
public void onVisibilityChanged(int visibility) {
481-
switch (visibility) {
482-
case View.GONE:
483-
getWindow().getDecorView().setSystemUiVisibility(
484-
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
485-
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
486-
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
487-
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
488-
| View.SYSTEM_UI_FLAG_FULLSCREEN
489-
| View.SYSTEM_UI_FLAG_IMMERSIVE);
490-
break;
491-
case View.VISIBLE:
492-
getWindow().getDecorView().setSystemUiVisibility(
493-
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
494-
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
495-
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
496-
}
478+
videoPlayerView.setControllerVisibilityListener((PlayerView.ControllerVisibilityListener) visibility -> {
479+
switch (visibility) {
480+
case View.GONE:
481+
getWindow().getDecorView().setSystemUiVisibility(
482+
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
483+
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
484+
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
485+
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
486+
| View.SYSTEM_UI_FLAG_FULLSCREEN
487+
| View.SYSTEM_UI_FLAG_IMMERSIVE);
488+
break;
489+
case View.VISIBLE:
490+
getWindow().getDecorView().setSystemUiVisibility(
491+
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
492+
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
493+
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
497494
}
498495
});
499496
}
@@ -622,7 +619,7 @@ public void onPlayerError(@NonNull PlaybackException error) {
622619
if (videoType == VIDEO_TYPE_DIRECT) {
623620
videoFileName = FilenameUtils.getName(videoDownloadUrl);
624621
} else {
625-
videoFileName = "imgur-" + FilenameUtils.getName(videoDownloadUrl);
622+
videoFileName = "Imgur-" + FilenameUtils.getName(videoDownloadUrl);
626623
}
627624
} else {
628625
videoDownloadUrl = intent.getStringExtra(EXTRA_VIDEO_DOWNLOAD_URL);
@@ -665,7 +662,7 @@ public void onFetchImgurVideoLinkSuccess(String videoUrl, String videoDownloadUr
665662
binding.getProgressBar().setVisibility(View.GONE);
666663
mVideoUri = Uri.parse(videoUrl);
667664
ViewVideoActivity.this.videoDownloadUrl = videoDownloadUrl;
668-
videoFileName = "imgur-" + FilenameUtils.getName(videoDownloadUrl);
665+
videoFileName = "Imgur-" + FilenameUtils.getName(videoDownloadUrl);
669666
// Prepare the player with the source.
670667
player.prepare();
671668
player.setMediaSource(new ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(MediaItem.fromUri(mVideoUri)));

app/src/main/java/ml/docilealligator/infinityforreddit/bottomsheetfragments/PostOptionsBottomSheetFragment.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package ml.docilealligator.infinityforreddit.bottomsheetfragments;
22

3+
import android.app.job.JobInfo;
4+
import android.app.job.JobScheduler;
35
import android.content.Context;
46
import android.content.Intent;
57
import android.os.Bundle;
8+
import android.os.PersistableBundle;
69
import android.view.LayoutInflater;
710
import android.view.View;
811
import android.view.ViewGroup;
@@ -24,6 +27,8 @@
2427
import ml.docilealligator.infinityforreddit.customviews.LandscapeExpandedRoundedBottomSheetDialogFragment;
2528
import ml.docilealligator.infinityforreddit.databinding.FragmentPostOptionsBottomSheetBinding;
2629
import ml.docilealligator.infinityforreddit.post.Post;
30+
import ml.docilealligator.infinityforreddit.services.DownloadMediaService;
31+
import ml.docilealligator.infinityforreddit.services.DownloadRedditVideoService;
2732

2833
/**
2934
* A simple {@link Fragment} subclass.
@@ -33,6 +38,7 @@
3338
public class PostOptionsBottomSheetFragment extends LandscapeExpandedRoundedBottomSheetDialogFragment {
3439

3540
private static final String EXTRA_POST = "EP";
41+
private static final String EXTRA_GALLERY_INDEX = "EGI";
3642

3743
private BaseActivity mBaseActivity;
3844
private Post mPost;
@@ -76,13 +82,44 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
7682
if (mPost != null) {
7783
switch (mPost.getPostType()) {
7884
case Post.IMAGE_TYPE:
85+
case Post.GALLERY_TYPE:
86+
binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE);
87+
binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_image);
7988
break;
8089
case Post.GIF_TYPE:
90+
binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE);
91+
binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_gif);
8192
break;
8293
case Post.VIDEO_TYPE:
94+
binding.downloadTextViewPostOptionsBottomSheetFragment.setVisibility(View.VISIBLE);
95+
binding.downloadTextViewPostOptionsBottomSheetFragment.setText(R.string.download_video);
8396
break;
84-
case Post.GALLERY_TYPE:
85-
break;
97+
}
98+
99+
if (binding.downloadTextViewPostOptionsBottomSheetFragment.getVisibility() == View.VISIBLE) {
100+
binding.downloadTextViewPostOptionsBottomSheetFragment.setOnClickListener(view -> {
101+
if (mPost.getPostType() == Post.VIDEO_TYPE) {
102+
if (!mPost.isRedgifs() && !mPost.isStreamable() && !mPost.isImgur()) {
103+
PersistableBundle extras = new PersistableBundle();
104+
extras.putString(DownloadRedditVideoService.EXTRA_VIDEO_URL, mPost.getVideoDownloadUrl());
105+
extras.putString(DownloadRedditVideoService.EXTRA_POST_ID, mPost.getId());
106+
extras.putString(DownloadRedditVideoService.EXTRA_SUBREDDIT, mPost.getSubredditName());
107+
extras.putInt(DownloadRedditVideoService.EXTRA_IS_NSFW, mPost.isNSFW() ? 1 : 0);
108+
109+
//TODO: contentEstimatedBytes
110+
JobInfo jobInfo = DownloadRedditVideoService.constructJobInfo(mBaseActivity, 5000000, extras);
111+
((JobScheduler) mBaseActivity.getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo);
112+
113+
dismiss();
114+
return;
115+
}
116+
}
117+
118+
JobInfo jobInfo = DownloadMediaService.constructJobInfo(mBaseActivity, 5000000, mPost, getArguments().getInt(EXTRA_GALLERY_INDEX, 0));
119+
((JobScheduler) mBaseActivity.getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(jobInfo);
120+
121+
dismiss();
122+
});
86123
}
87124

88125
binding.addToPostFilterTextViewPostOptionsBottomSheetFragment.setOnClickListener(view -> {

app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchPost.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
import androidx.annotation.NonNull;
66
import androidx.annotation.Nullable;
7+
import androidx.annotation.WorkerThread;
78

9+
import java.io.IOException;
810
import java.util.concurrent.Executor;
911

1012
import ml.docilealligator.infinityforreddit.account.Account;
@@ -52,6 +54,29 @@ public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
5254
});
5355
}
5456

57+
@WorkerThread
58+
@Nullable
59+
public static Post fetchPostSync(Retrofit retrofit, String id, @Nullable String accessToken,
60+
@NonNull String accountName) {
61+
Call<String> postCall;
62+
if (accountName.equals(Account.ANONYMOUS_ACCOUNT)) {
63+
postCall = retrofit.create(RedditAPI.class).getPost(id);
64+
} else {
65+
postCall = retrofit.create(RedditAPI.class).getPostOauth(id, APIUtils.getOAuthHeader(accessToken));
66+
}
67+
try {
68+
Response<String> response = postCall.execute();
69+
if (response.isSuccessful()) {
70+
return ParsePost.parsePostSync(response.body());
71+
} else {
72+
return null;
73+
}
74+
75+
} catch (IOException e) {
76+
return null;
77+
}
78+
}
79+
5580
public static void fetchRandomPost(Executor executor, Handler handler, Retrofit retrofit, boolean isNSFW,
5681
FetchRandomPostListener fetchRandomPostListener) {
5782
Call<String> call;

app/src/main/java/ml/docilealligator/infinityforreddit/post/FetchStreamableVideo.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.os.Handler;
44

55
import androidx.annotation.Nullable;
6+
import androidx.annotation.WorkerThread;
67

78
import org.json.JSONException;
89
import org.json.JSONObject;
@@ -50,6 +51,35 @@ public static void fetchStreamableVideo(Executor executor, Handler handler, Prov
5051
});
5152
}
5253

54+
@WorkerThread
55+
@Nullable
56+
public static StreamableVideo fetchStreamableVideoSync(Provider<StreamableAPI> streamableApiProvider,
57+
String videoUrl) {
58+
try {
59+
Response<String> response = streamableApiProvider.get().getStreamableData(videoUrl).execute();
60+
if (response.isSuccessful()) {
61+
JSONObject jsonObject = new JSONObject(response.body());
62+
String title = jsonObject.getString(JSONUtils.TITLE_KEY);
63+
JSONObject filesObject = jsonObject.getJSONObject(JSONUtils.FILES_KEY);
64+
StreamableVideo.Media mp4 = parseMedia(filesObject.getJSONObject(JSONUtils.MP4_KEY));
65+
StreamableVideo.Media mp4MobileTemp = null;
66+
if (filesObject.has(JSONUtils.MP4_MOBILE_KEY)) {
67+
mp4MobileTemp = parseMedia(filesObject.getJSONObject(JSONUtils.MP4_MOBILE_KEY));
68+
}
69+
if (mp4 == null && mp4MobileTemp == null) {
70+
return null;
71+
}
72+
StreamableVideo.Media mp4Mobile = mp4MobileTemp;
73+
return new StreamableVideo(title, mp4, mp4Mobile);
74+
} else {
75+
return null;
76+
}
77+
} catch (IOException | JSONException e) {
78+
e.printStackTrace();
79+
return null;
80+
}
81+
}
82+
5383
public static void fetchStreamableVideoInRecyclerViewAdapter(Executor executor, Handler handler, Call<String> streamableCall,
5484
FetchVideoLinkListener fetchVideoLinkListener) {
5585
executor.execute(() -> {

app/src/main/java/ml/docilealligator/infinityforreddit/post/ImgurMedia.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ public String getLink() {
6464

6565
public String getFileName() {
6666
if (type == TYPE_VIDEO) {
67-
return "imgur-" + id + ".mp4";
67+
return "Imgur-" + id + ".mp4";
6868
}
6969

70-
return "imgur-" + id + ".jpg";
70+
return "Imgur-" + id + ".jpg";
7171
}
7272

7373
@Override

app/src/main/java/ml/docilealligator/infinityforreddit/post/ParsePost.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import android.text.Html;
66
import android.text.TextUtils;
77

8+
import androidx.annotation.Nullable;
9+
import androidx.annotation.WorkerThread;
10+
811
import org.json.JSONArray;
912
import org.json.JSONException;
1013
import org.json.JSONObject;
@@ -82,9 +85,6 @@ public static String getLastItem(String response) {
8285

8386

8487
public static void parsePost(Executor executor, Handler handler, String response, ParsePostListener parsePostListener) {
85-
PostFilter postFilter = new PostFilter();
86-
postFilter.allowNSFW = true;
87-
8888
executor.execute(() -> {
8989
try {
9090
JSONArray allData = new JSONArray(response).getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
@@ -102,6 +102,22 @@ public static void parsePost(Executor executor, Handler handler, String response
102102
});
103103
}
104104

105+
@WorkerThread
106+
@Nullable
107+
public static Post parsePostSync(String response) {
108+
try {
109+
JSONArray allData = new JSONArray(response).getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY).getJSONArray(JSONUtils.CHILDREN_KEY);
110+
if (allData.length() == 0) {
111+
return null;
112+
}
113+
JSONObject data = allData.getJSONObject(0).getJSONObject(JSONUtils.DATA_KEY);
114+
return parseBasicData(data);
115+
} catch (JSONException e) {
116+
e.printStackTrace();
117+
return null;
118+
}
119+
}
120+
105121
public static void parseRandomPost(Executor executor, Handler handler, String response, boolean isNSFW,
106122
ParseRandomPostListener parseRandomPostListener) {
107123
executor.execute(() -> {

0 commit comments

Comments
 (0)