Reddit Android App Development with Source Code.
Need some career advice or prepping for an Android developer interview? Hit me up on Topmate.io, and let's chat!
In this tutorial of Build that App. We will teach you how you can create your Reddit App in Android Studio using Java Programming Language.
However this app won’t be like the original Reddit App available in the play store. Rather it will have a swipe layout just like popular dating app Tinder. Which means you will be able to swipe your feeds in any direction.
For this we will be using yuyakaido library CardStackViewto achieve the desired layout.
Reddit Android App Development
Getting Started
Create a new Android Studio Project with Empty Activity. Go to build.gradle (app) and add following dependencies:
//TinderCards Library
implementation "com.yuyakaido.android:card-stack-view:2.2.1"
//Picasso
implementation 'com.squareup.picasso:picasso:2.71828'
//OKHTTP
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
//Glide
implementation 'com.github.bumptech.glide:glide:4.8.0'
//GSON
implementation 'com.google.code.gson:gson:2.8.2'
Making Layouts
Once the build Sync is finished, go to activity_main.xml in the res folder (See on the left side in the Project Panel). And add the following lines of code to it inside the ConstraintLayout Widget:
<com.yuyakaido.android.cardstackview.CardStackView
android:id="@+id/card_stack_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
We’ve now added the CardStackView, this is where the cards will be displayed. Now let’s make the layout for our cards.
Here is the rough draft of how our card will look like:
The finalized UI of the card layout looks like the following:
The XML code to be added in a new layout file named item_spot.xml to achieve such a layout as shown above is as follows:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"
android:foreground="?attr/selectableItemBackground"
app:cardUseCompatPadding="true"
app:cardPreventCornerOverlap="false"
app:cardCornerRadius="10dp"
android:elevation="10dp"
app:layout_constraintCircleRadius="5dp"
app:cardBackgroundColor="@android:color/white">
<ImageView
android:src="@drawable/board"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"/>
<ImageView
android:id="@+id/item_thumb_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="center"/>
<ImageView
android:id="@+id/item_chota_image"
android:layout_marginTop="50dp"
android:layout_marginBottom="120dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
android:adjustViewBounds="true"/>
<com.google.android.exoplayer2.ui.PlayerView
android:layout_marginBottom="50dp"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/video_player"/>
<LinearLayout
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:textColor="@color/white"
android:shadowDy="2"
android:shadowColor="#000"
android:shadowRadius="10"
android:id="@+id/item_subreddit_name"
android:textSize="12sp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="r/subreddit_name"/>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:textColor="@color/white"
android:shadowDy="2"
android:shadowRadius="10"
android:shadowColor="#000"
android:textSize="10sp"
android:id="@+id/item_pubDate"
android:textAlignment="viewEnd"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Author Name"/>
<TextView
android:id="@+id/item_auth_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:shadowColor="#000"
android:shadowDy="2"
android:shadowRadius="10"
android:text="By Author Name"
android:textAlignment="viewEnd"
android:textColor="@color/white"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_marginTop="50dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1"
android:layout_gravity="bottom"
android:padding="10dp"
android:background="@drawable/layout_bg">
<ScrollView
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:text="Learn Text"
android:id="@+id/item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textColor="@android:color/white"
android:textSize="17sp"/>
<TextView
android:text="Know Text"
android:id="@+id/item_subTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="all"
android:clickable="true"
android:focusable="true"
android:textStyle="bold"
android:textColor="@android:color/white"
android:textSize="12sp"/>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
app:fabCustomSize="35dp"
android:id="@+id/fab_comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hapticFeedbackEnabled="true"
android:src="@drawable/chat"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#22bf00ff"/>
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
app:fabCustomSize="35dp"
android:id="@+id/fab_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hapticFeedbackEnabled="true"
android:src="@drawable/share"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#22ff0004"/>
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
app:fabCustomSize="35dp"
android:id="@+id/fab_down"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hapticFeedbackEnabled="true"
android:src="@drawable/download"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#2200ff97"/>
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
android:id="@+id/fab_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabCustomSize="35dp"
android:hapticFeedbackEnabled="true"
android:src="@drawable/video"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#2200ff97"/>
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
android:id="@+id/fab_copy"
android:layout_width="wrap_content"
app:fabCustomSize="35dp"
android:layout_height="wrap_content"
android:hapticFeedbackEnabled="true"
android:src="@drawable/copy"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#2200ff97"/>
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
android:id="@+id/fab_maximise"
app:fabCustomSize="35dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hapticFeedbackEnabled="true"
android:src="@drawable/maximize"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#2200ff97"/>
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
android:id="@+id/fab_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabCustomSize="35dp"
android:hapticFeedbackEnabled="true"
android:src="@drawable/link"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#2200ff97"/>
<android.support.design.widget.FloatingActionButton
android:layout_margin="10dp"
android:layout_weight="1"
android:id="@+id/fab_wallpaper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabCustomSize="35dp"
android:tint="@color/colorAccent"
android:hapticFeedbackEnabled="true"
android:src="@drawable/ic_wallpaper"
app:backgroundTint="@android:color/white"
app:fabSize="auto"
app:rippleColor="#2200ff97"/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
Coding the Reddit Android App Development
Now go to MainActivity.java and Let’s first create an AsyncTask to get the data from Reddit.
Before calling an Asynctask, we much know from which URL we are going to fetch data. As per Reddit API we can easily fetch a public data, subject to a limit of maximum 100 feeds at a time. By simply adding /.json&after=after_tag&limit=100 as a suffix to any of its URL.
.json is used to get data in JSON format (you can get in XML)
after and before tag parameters are used in case of pagination. It is useful,if the user wants to view more than 100 feeds.
Limit: The number can be any upto 100. We’re using 50 in our example to make it easier for our app to handle data.
@SuppressLint("StaticFieldLeak")
public class getFeed extends AsyncTask<String,Void,String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setMessage("Getting Feed...");
progressDialog.show();
}
@Override
protected String doInBackground(String... strings) {
OkHttpClient client = new OkHttpClient();
if(strings.length != 0) {
Request request = new Request.Builder()
// .url("https://www.reddit.com/" + strings[0] + ".json?raw_json=1&after=" + after + "&limit=50")
.url("https://www.reddit.com/r/earthporn/.json?raw_json=1&after=" + after + "&limit=50")
.build();
try (Response response = client.newCall(request).execute()) {
assert response.body() != null;
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Request request = new Request.Builder()
// .url("https://www.reddit.com/" + strings[0] + ".json?raw_json=1&after=" + after + "&limit=50")
.url("https://www.reddit.com/r/earthporn/.json?raw_json=1&after=" + after + "&limit=50")
.build();
try (Response response = client.newCall(request).execute()) {
assert response.body() != null;
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
postArrayList.clear();
try {
if(s != null) {
JSONObject jsonObject = new JSONObject(s);
if(jsonObject.has("data")) {
JSONObject dataJSON = jsonObject.getJSONObject("data");
modhash = dataJSON.getString("modhash");
JSONArray childrenArray = dataJSON.getJSONArray("children");
dist = dataJSON.getLong("dist");
after = dataJSON.getString("after");
before = dataJSON.getString("before");
for (int i = 0; i < childrenArray.length(); i++) {
JSONObject item = childrenArray.getJSONObject(i);
JSONObject items = item.getJSONObject("data");
String subreddit = items.getString("subreddit");
String title = items.getString("title");
String selftext = items.getString("selftext");
String thumbnail = items.getString("thumbnail");
String author_flair_css_class = items.getString("author_flair_css_class");
String over_18 = items.getString("over_18");
String author = items.getString("author");
String url = items.getString("url");
String is_video = items.getString("is_video");
String permalink = "";
if (!items.getString("permalink").isEmpty()) {
permalink = items.getString("permalink");
}
Long ups = items.getLong("ups");
Long created = items.getLong("created");
Long num_comments = items.getLong("num_comments");
Long num_crossposts = items.getLong("num_crossposts");
String type = "hi";
String post_hint = "hi";
String is_gif = "false";
if (items.has("post_hint")) {
post_hint = items.getString("post_hint");
}
// NOT CrossPost
// if(!items.has("crosspost_parent_list")){
if (items.has("preview") && post_hint.equals("image")) {
JSONObject preview = items.getJSONObject("preview");
JSONArray images = preview.getJSONArray("images");
JSONObject zero = images.getJSONObject(0);
JSONObject source = zero.getJSONObject("source");
long width = source.getLong("width");
if (width > 1079) {
type = "BCGR";
JSONArray resolutions = zero.getJSONArray("resolutions");
int size = resolutions.length() - 1;
JSONObject thumbstar = resolutions.getJSONObject(size);
thumbnail = thumbstar.getString("url");
} else {
type = "MEME";
}
} else if (/*!items.has("preview") &&*/ url.contains("reddit.com") && is_video.equals("false")) {
type = "TEXT";
} else if (post_hint.equals("link") || post_hint.equals("rich:video") || post_hint.equals("hi") && !url.contains("reddit.com")) {
type = "LINK";
if (items.has("preview")) {
JSONObject preview = items.getJSONObject("preview");
JSONArray images = preview.getJSONArray("images");
JSONObject zero = images.getJSONObject(0);
JSONObject source = zero.getJSONObject("source");
thumbnail = source.getString("url");
if (preview.has("reddit_video_preview")) {
JSONObject reddit_video_preview = preview.getJSONObject("reddit_video_preview");
is_gif = reddit_video_preview.getString("is_gif");
if (is_video.equals("false") && is_gif.equals("true")) {
type = "VIDS";
url = reddit_video_preview.getString("dash_url");
}
}
}
} else if (is_video.equals("true")) {
type = "VIDS";
if (items.has("media")) {
JSONObject media = items.getJSONObject("media");
JSONObject reddit_video = media.getJSONObject("reddit_video");
url = reddit_video.getString("dash_url");
}
}
postArrayList.add(new Model_Data(subreddit, title, selftext, thumbnail, author_flair_css_class, post_hint, over_18, author, url, is_video, permalink, ups, created, num_comments, num_crossposts, type, is_gif));
}
if(cardStackView.getAdapter() == null){
adapter = new CardStackAdapter(postArrayList);
cardStackView.setAdapter(adapter);
}
adapter.notifyDataSetChanged();
cardStackView.setAdapter(adapter);
progressDialog.dismiss();
} else {
showToast("SubReddit Invalid");
progressDialog.dismiss();
}
} else {
new AlertDialog.Builder(MainActivity.this)
.setTitle("Unable to Fetch Data")
.setMessage("Please Refresh or check your Internet Connection")
// Specifying a listener allows you to take an action before dismissing the dialog.
// The dialog is automatically dismissed when a dialog button is clicked.
.setPositiveButton("Refresh Data", (dialog, which) -> {
// Continue with delete operation
new getFeed().execute();
})
// A null listener allows the button to dismiss the dialog and take no further action.
.setNegativeButton("Exit App", (dialog, which) -> finish())
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
In onPostExecute() method of the Asynctask, you will notice that there are various variables we have used. They are important to know the type of feed and also to display data in card view.
Here is the code for the Adapter to show card:
public class CardStackAdapter extends CardStackView.Adapter<RecyclerView.ViewHolder>{
private List<Model_Data> postArrayList;
CardStackAdapter(List<Model_Data> postArrayList) {
this.postArrayList = postArrayList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
switch(i){
case 10:
View view= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.rec_ads,viewGroup,false);
return new AdViewHolder(view);
default:
View cardview= LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_spot,viewGroup,false);
return new CardViewHolder(cardview);
}
}
@Override
public int getItemViewType(int position) {
return position % 20;
}
@SuppressLint("RestrictedApi")
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) {
switch (viewHolder.getItemViewType()){
case 10:
AdViewHolder adViewHolder = (AdViewHolder) viewHolder;
loadNativeAd(adViewHolder.itemView.getContext());
adViewHolder.shareApp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO: SHARE APP
}
});
break;
default:
CardViewHolder cardViewHolder = (CardViewHolder) viewHolder;
Model_Data post = postArrayList.get(i);
String AuthorName = "by " + post.getAuthor();
cardViewHolder.authName.setText(AuthorName);
cardViewHolder.title.setText(post.getTitle());
cardViewHolder.subTitle.setText(post.getSelftext());
String timeAgo = GetTimeAgo.getTimeAgo(post.getCreated(),cardViewHolder.itemView.getContext());
cardViewHolder.pubDate.setText(timeAgo);
cardViewHolder.thumbImage.setImageDrawable(null);
cardViewHolder.playerView.setVisibility(View.GONE);
String getSub = "r/" + post.getSubreddit();
cardViewHolder.subredditName.setText(getSub);
// cardViewHolder.thumbImage.setBackground(getResources().getDrawable(R.drawable.mona));
cardViewHolder.fMsg.setOnClickListener(v -> {
//TODO: MESSAGES / COMMENTS
});
// cardViewHolder.itemView.setOnTouchListener(new View.OnTouchListener() {
// @Override
// public boolean onTouch(View v, MotionEvent event) {
// if(MotionEvent.ACTION_UP == event.getActionMasked()){
// showToast("Swiped Up");
// return true;
// }
// return false;
// }
// });
cardViewHolder.fDown.setVisibility(View.GONE);
cardViewHolder.fVideo.setVisibility(View.GONE);
cardViewHolder.fCopy.setVisibility(View.GONE);
cardViewHolder.fResize.setVisibility(View.GONE);
cardViewHolder.fWallpaper.setVisibility(View.GONE);
cardViewHolder.fLink.setVisibility(View.GONE);
cardViewHolder.thumbImage.setVisibility(View.INVISIBLE);
cardViewHolder.chotaImage.setVisibility(View.VISIBLE);
switch (post.getType()) {
case "BCGR":
cardViewHolder.fDown.setVisibility(View.VISIBLE);
cardViewHolder.fResize.setVisibility(View.VISIBLE);
cardViewHolder.fWallpaper.setVisibility(View.VISIBLE);
cardViewHolder.thumbImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
//COMMENT SYSTEM
cardViewHolder.fMsg.setOnClickListener(v -> mBottomSheetDialog.show());
mBottomSheetDialog.setOnShowListener(dialog -> new CommentsShow().execute(post.getPermalink()));
Glide.with(getApplicationContext()).load(post.getThumbnail()).into(cardViewHolder.thumbImage);
Glide.with(getApplicationContext()).load(post.getThumbnail()).into(cardViewHolder.chotaImage);
cardViewHolder.fShare.setOnClickListener(v -> shareItem(post.getUrl(), post.getTitle(), post.getType()));
cardViewHolder.fWallpaper.setOnClickListener(v -> {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 123);
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
showToast("Need Permission to access storage for Downloading Image");
} else {
new AlertDialog.Builder(MainActivity.this)
.setTitle("Change Background Wallpaper?")
.setMessage("Are you sure you want to change your wallpaper to currently selected Image?")
// Specifying a listener allows you to take an action before dismissing the dialog.
// The dialog is automatically dismissed when a dialog button is clicked.
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
// Continue with delete operation
new SetWallpaper().execute(post.getUrl());
})
// A null listener allows the button to dismiss the dialog and take no further action.
.setNegativeButton(android.R.string.no, null)
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
});
// RESIZE SCALE
cardViewHolder.fResize.setOnClickListener(v -> {
if (cardViewHolder.chotaImage.getVisibility() == View.INVISIBLE) {
cardViewHolder.chotaImage.setVisibility(View.VISIBLE);
cardViewHolder.thumbImage.setVisibility(View.INVISIBLE);
} else {
cardViewHolder.chotaImage.setVisibility(View.INVISIBLE);
cardViewHolder.thumbImage.setVisibility(View.VISIBLE);
}
});
//DOWNLOAD IMAGE
cardViewHolder.fDown.setOnClickListener(v -> DownloadImage(post.getUrl()));
break;
case "MEME":
//COMMENT SYSTEM
mBottomSheetDialog.setOnShowListener(dialog -> new CommentsShow().execute(post.getPermalink()));
cardViewHolder.fMsg.setOnClickListener(v -> mBottomSheetDialog.show());
cardViewHolder.fDown.setVisibility(View.VISIBLE);
cardViewHolder.fResize.setVisibility(View.VISIBLE);
cardViewHolder.thumbImage.setScaleType(ImageView.ScaleType.FIT_START);
Glide.with(getApplicationContext()).load(post.getUrl()).into(cardViewHolder.thumbImage);
Glide.with(getApplicationContext()).load(post.getUrl()).into(cardViewHolder.chotaImage);
cardViewHolder.fShare.setOnClickListener(v -> shareItem(post.getUrl(), post.getTitle(), post.getType()));
//RESIZE SCALE
cardViewHolder.fResize.setOnClickListener(v -> {
if (cardViewHolder.chotaImage.getVisibility() == View.INVISIBLE) {
cardViewHolder.chotaImage.setVisibility(View.VISIBLE);
cardViewHolder.thumbImage.setVisibility(View.INVISIBLE);
} else {
cardViewHolder.chotaImage.setVisibility(View.INVISIBLE);
cardViewHolder.thumbImage.setVisibility(View.VISIBLE);
}
});
//DOWNLOAD IMAGE
cardViewHolder.fDown.setOnClickListener(v -> DownloadImage(post.getUrl()));
break;
case "VIDS":
cardViewHolder.fDown.setVisibility(View.VISIBLE);
cardViewHolder.fVideo.setVisibility(View.VISIBLE);
//COMMENT SYSTEM
mBottomSheetDialog.setOnShowListener(dialog -> new CommentsShow().execute(post.getPermalink()));
cardViewHolder.fMsg.setOnClickListener(v -> mBottomSheetDialog.show());
if (post.getPost_hint().equals("hosted:video") || post.getPost_hint().equals("link")) {
cardViewHolder.playerView.setVisibility(View.VISIBLE);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(cardViewHolder.itemView.getContext(),
com.google.android.exoplayer2.util.Util.getUserAgent(cardViewHolder.itemView.getContext(), "ExoPlayer"));
Uri uri = Uri.parse(post.getUrl());
DashMediaSource dashMediaSource = new DashMediaSource(uri, dataSourceFactory,
new DefaultDashChunkSource.Factory(dataSourceFactory), null, null);
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelector trackSelector = new DefaultTrackSelector(new AdaptiveTrackSelection.Factory(bandwidthMeter));
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(cardViewHolder.itemView.getContext(), trackSelector);
// VIDEO PLAY
cardViewHolder.fVideo.setOnClickListener(v -> {
simpleExoPlayer.prepare(dashMediaSource);
simpleExoPlayer.setPlayWhenReady(true);
simpleExoPlayer.setVolume(0);
simpleExoPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
cardViewHolder.playerView.setPlayer(simpleExoPlayer);
});
if (cardViewHolder.playerView.getPlayer() != null) {
//TODO: ERROR
if (cardViewHolder.playerView.getVisibility() == View.INVISIBLE) {
cardViewHolder.playerView.getPlayer().setPlayWhenReady(false);
cardViewHolder.playerView.getPlayer().seekTo(0);
cardViewHolder.playerView.getPlayer().stop();
swiped = false;
}
}
cardViewHolder.fShare.setOnClickListener(v -> shareItem(post.getUrl(), post.getTitle(), post.getType()));
cardViewHolder.fDown.setOnClickListener(v -> {
//DownloadImage(post.getUrl());
//TODO: Download Video
new ProgressBack().execute(post.getUrl());
});
} else if (post.getPost_hint().equals("rich:video")) {
// showToast("Rich Video");
//TODO:RIchVIDEO
/* Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(post.getUrl()));
startActivity(browserIntent);
Toast.makeText(cardViewHolder.itemView.getContext(),"Opening Video in Browser",Toast.LENGTH_SHORT).show();*/
cardViewHolder.fShare.setOnClickListener(v -> shareItem(post.getUrl(), post.getTitle(), post.getType()));
cardViewHolder.fDown.setOnClickListener(v -> {
//DownloadImage(post.getUrl());
//TODO: Download Video
new ProgressBack().execute(post.getUrl());
});
}
break;
case "TEXT":
cardViewHolder.fCopy.setVisibility(View.VISIBLE);
cardViewHolder.fLink.setVisibility(View.VISIBLE);
//COMMENT SYSTEM
mBottomSheetDialog.setOnShowListener(dialog -> new CommentsShow().execute(post.getPermalink()));
cardViewHolder.fMsg.setOnClickListener(v -> mBottomSheetDialog.show());
//Copy
cardViewHolder.fCopy.setOnClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
String text = post.getTitle() + "\n\n" + post.getSelftext();
ClipData clip = ClipData.newPlainText("popcorn", text);
clipboard.setPrimaryClip(clip);
showToast("Story copied to Clipboard");
});
cardViewHolder.fLink.setOnClickListener(v -> {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(post.getUrl()));
startActivity(browserIntent);
Toast.makeText(cardViewHolder.itemView.getContext(), "Opening Story in Browser", Toast.LENGTH_SHORT).show();
});
cardViewHolder.fShare.setOnClickListener(v -> {
String shareBody = post.getTitle() + " Send using Popcorn for Reddit!";
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, "Popcorn for Reddit");
sharingIntent.putExtra(Intent.EXTRA_TEXT, shareBody);
startActivity(Intent.createChooser(sharingIntent, "Share Text Using..."));
});
break;
case "LINK":
cardViewHolder.fLink.setVisibility(View.VISIBLE);
cardViewHolder.fCopy.setVisibility(View.VISIBLE);
cardViewHolder.thumbImage.setScaleType(ImageView.ScaleType.FIT_START);
Glide.with(getApplicationContext()).load(post.getThumbnail()).into(cardViewHolder.thumbImage);
//COMMENT SYSTEM
mBottomSheetDialog.setOnShowListener(dialog -> new CommentsShow().execute(post.getPermalink()));
cardViewHolder.fMsg.setOnClickListener(v -> mBottomSheetDialog.show());
//Copy
cardViewHolder.fCopy.setOnClickListener(v -> {
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
String text = post.getTitle() + " Read more here: " + post.getUrl() + "\n\n Send using Popcorn for Reddit";
ClipData clip = ClipData.newPlainText("popcorn", text);
clipboard.setPrimaryClip(clip);
Toast.makeText(cardViewHolder.itemView.getContext(), "Link copied to Clipboard", Toast.LENGTH_SHORT).show();
});
//OPEN LINK
cardViewHolder.fLink.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(post.getUrl()));
startActivity(intent);
showToast("Opening Link in Browser!");
});
//SHARE LINK
cardViewHolder.fShare.setOnClickListener(v -> {
String shareBody = post.getTitle() + " \n\n" + post.getUrl() + " \n\nSent using 'Popcorn for Reddit'";
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, post.getTitle());
sharingIntent.putExtra(Intent.EXTRA_TEXT, shareBody);
startActivity(Intent.createChooser(sharingIntent, "Share Link Using..."));
});
break;
case "ILNK":
//SHARE, COPY, DOWNLOAD
break;
}
//Customised
if(post.getSubreddit().equals("news")){
cardViewHolder.thumbImage.setBackground(getResources().getDrawable(R.drawable.newspaper));
//SHARE LINK
cardViewHolder.fShare.setOnClickListener(v -> {
String shareBody = post.getUrl();
Intent sharingIntent = new Intent(Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(Intent.EXTRA_SUBJECT, post.getTitle());
sharingIntent.putExtra(Intent.EXTRA_TEXT, shareBody);
startActivity(Intent.createChooser(sharingIntent, "Share NEWS Using..."));
});
//COMMENT SYSTEM
mBottomSheetDialog.setOnShowListener(dialog -> new CommentsShow().execute(post.getPermalink()));
cardViewHolder.fMsg.setOnClickListener(v -> mBottomSheetDialog.show());
}
if(i == postArrayList.size()-1){
new getFeed().execute();
}
//cardViewHolder.fMsg.setVisibility(View.GONE);
// mBottomSheetDialog.setOnShowListener(dialog -> new CommentsShow().execute(post.getPermalink()));
//
// cardViewHolder.fMsg.setOnClickListener(v -> mBottomSheetDialog.show());
String myLinkText = cardViewHolder.subTitle.getText().toString();
Spannable spannable = new SpannableString( Html.fromHtml(myLinkText) );
Linkify.addLinks(spannable, Linkify.WEB_URLS);
cardViewHolder.subTitle.setMovementMethod(EnhancedLinkMovementMethod.getInstance());
cardViewHolder.subTitle.setText(spannable, TextView.BufferType.SPANNABLE);
URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
for (URLSpan urlSpan : spans) {
LinkSpan linkSpan = new LinkSpan(urlSpan.getURL());
int spanStart = spannable.getSpanStart(urlSpan);
int spanEnd = spannable.getSpanEnd(urlSpan);
spannable.setSpan(linkSpan, spanStart, spanEnd, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.removeSpan(urlSpan);
}
cardViewHolder.subTitle.setOnClickListener(v -> showToast("Double click to open a link!"));
break;
}
}
@Override
public int getItemCount() {
return postArrayList.size();
}
class CardViewHolder extends RecyclerView.ViewHolder {
ImageView thumbImage, chotaImage;
TextView authName, pubDate, title, subTitle, subredditName;
PlayerView playerView;
FloatingActionButton fMsg, fShare, fDown, fVideo, fCopy, fResize,fLink, fWallpaper;
CardViewHolder(@NonNull View itemView) {
super(itemView);
chotaImage = itemView.findViewById(R.id.item_chota_image);
thumbImage = itemView.findViewById(R.id.item_thumb_image);
authName = itemView.findViewById(R.id.item_auth_name);
pubDate = itemView.findViewById(R.id.item_pubDate);
title = itemView.findViewById(R.id.item_title);
subTitle = itemView.findViewById(R.id.item_subTitle);
playerView = itemView.findViewById(R.id.video_player);
subredditName = itemView.findViewById(R.id.item_subreddit_name);
fMsg = itemView.findViewById(R.id.fab_comments);
fShare = itemView.findViewById(R.id.fab_share);
fDown = itemView.findViewById(R.id.fab_down);
fVideo = itemView.findViewById(R.id.fab_video);
fCopy = itemView.findViewById(R.id.fab_copy);
fResize = itemView.findViewById(R.id.fab_maximise);
fLink = itemView.findViewById(R.id.fab_link);
fWallpaper = itemView.findViewById(R.id.fab_wallpaper);
}
}
}
In the Adapter above we have also, as shown above, using an Ad layout if in case you want to show ads as well. Here are some extra line of codes for some functions used in the adapter above.
private class LinkSpan extends URLSpan {
private LinkSpan(String url) {
super(url);
}
@Override
public void onClick(View view) {
String url = getURL();
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(browserIntent);
}
}
void DownloadImage(String ImageUrl) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 123);
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 123);
showToast("Need Permission to access storage for Downloading Image");
} else {
showToast("Downloading Image...");
new DownloadsImage().execute(ImageUrl);
}
}
@SuppressLint("StaticFieldLeak")
class CommentsShow extends AsyncTask<String,Void, String>{
@Override
protected void onPreExecute() {
super.onPreExecute();
modelComments.clear();
showToast("Loading Comments");
mCommentsProgress.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(String... strings) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://www.reddit.com" + strings[0] + ".json")
.build();
Response response;
try {
response = client.newCall(request).execute();
assert response.body() != null;
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
return "error";
}
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
mCommentsProgress.setVisibility(View.GONE);
try {
JSONArray jsonArray = new JSONArray(s);
JSONObject jsonObject = jsonArray.getJSONObject(1);
JSONObject dataObject = jsonObject.getJSONObject("data");
JSONArray childrenArray = dataObject.getJSONArray("children");
for( int i = 0; i < childrenArray.length(); i++){
JSONObject childObject = childrenArray.getJSONObject(i);
JSONObject dataChildObject = childObject.getJSONObject("data");
String author, body;
long timestamp, ups, downs;
if(dataChildObject.optString("author").isEmpty()){
author = "none";
} else {
author = dataChildObject.getString("author");
}
if(dataChildObject.optString("body").isEmpty()){
body = "none";
} else {
body = dataChildObject.getString("body");
}
if(dataChildObject.optLong("created") == 0){
timestamp = System.currentTimeMillis();
} else {
timestamp = dataChildObject.optLong("created");
}
if(dataChildObject.optLong("ups") == 0){
ups = 0;
} else {
ups = dataChildObject.optLong("ups");
}
if(dataChildObject.optLong("downs") == 0){
downs = 0;
} else {
downs = dataChildObject.optLong("downs");
}
// timestamp = dataChildObject.getLong("created");
// ups = dataChildObject.getLong("ups");
// downs = dataChildObject.getLong("downs");
Model_Comment model_comment = new Model_Comment(author,body,timestamp,ups,downs);
modelComments.add(model_comment);
//TODO: HERE
}
commentsAdapter = new CommentsAdapter(sheetView.getContext(),modelComments);
commentsRecycler.setAdapter(commentsAdapter);
commentsAdapter.notifyDataSetChanged();
} catch (JSONException e) {
showToast(e.getMessage());
}
}
}
public class CommentsAdapter extends RecyclerView.Adapter<CommentsAdapter.CommentsViewHolder>{
private Context context;
private List<Model_Comment> mRecyclerViewItems;
CommentsAdapter(Context context, List<Model_Comment> mRecyclerViewItems) {
this.context = context;
this.mRecyclerViewItems = mRecyclerViewItems;
}
@NonNull
@Override
public CommentsViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.rec_comments,viewGroup,false);
return new CommentsViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull CommentsViewHolder commentsViewHolder, int i) {
Model_Comment comment = mRecyclerViewItems.get(i);
commentsViewHolder.body.setText(comment.getBody());
commentsViewHolder.author.setText(comment.getAuthor());
String time = GetTimeAgo.getTimeAgo(comment.getCreated(),commentsViewHolder.itemView.getContext());
commentsViewHolder.createdOn.setText(time);
commentsViewHolder.ups.setText(String.valueOf(comment.getUps()));
commentsViewHolder.downs.setText(String.valueOf(comment.getDowns()));
}
@Override
public int getItemCount() {
if(mRecyclerViewItems.size() < 1){
noImage.setVisibility(View.VISIBLE);
} else {
noImage.setVisibility(View.GONE);
}
return mRecyclerViewItems.size();
}
class CommentsViewHolder extends RecyclerView.ViewHolder{
TextView body, author, createdOn, ups, downs;
CommentsViewHolder(@NonNull View itemView) {
super(itemView);
body = itemView.findViewById(R.id.item_comment);
author = itemView.findViewById(R.id.item_author);
createdOn = itemView.findViewById(R.id.item_timeago);
ups = itemView.findViewById(R.id.item_up);
downs = itemView.findViewById(R.id.item_down);
}
}
}
@SuppressLint("StaticFieldLeak")
class SetWallpaper extends AsyncTask<String, Void, Void>{
@Override
protected void onPreExecute() {
super.onPreExecute();
showToast("Getting Image...");
showToast("Large images may take sometime!");
}
@Override
protected Void doInBackground(String... strings) {
Bitmap result;
try {
result = Picasso.get()
.load(strings[0]).get();
WallpaperManager wallpaperManager = WallpaperManager.getInstance(MainActivity.this);
try {
wallpaperManager.setBitmap(result);
} catch (IOException ex) {
showToast(ex.getMessage());
}
} catch (IOException e) {
showToast(e.getMessage());
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
showToast("Wallpaper Set Successfully!");
}
}
@SuppressLint("StaticFieldLeak")
class DownloadsImage extends AsyncTask<String, Void,Void>{
@Override
protected Void doInBackground(String... strings) {
URL url = null;
try {
url = new URL(strings[0]);
} catch (MalformedURLException e) {
// e.printStackTrace();
showToast(e.getMessage());
}
Bitmap bm = null;
try {
bm = BitmapFactory.decodeStream(Objects.requireNonNull(url).openConnection().getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
//Create Path to save Image
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES+ "/Popcorn"); //Creates app specific folder
if(!path.exists()) {
path.mkdirs();
}
File imageFile = new File(path, String.valueOf(System.currentTimeMillis())+".png"); // Imagename.png
FileOutputStream out = null;
try {
out = new FileOutputStream(imageFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try{
Objects.requireNonNull(bm).compress(Bitmap.CompressFormat.PNG, 100, out); // Compress Image
assert out != null;
out.flush();
out.close();
// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(MainActivity.this,new String[] { imageFile.getAbsolutePath() }, null, (path1, uri) -> {
// Log.i("ExternalStorage", "Scanned " + path + ":");
// Log.i("ExternalStorage", "-> uri=" + uri);
});
} catch(Exception ignored) {
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
showToast("Image Saved!");
}
}
public void shareItem(String url, String Title, String Type){
if(!Type.equals("VIDS")) {
showToast("Please Wait, we're getting Image to share...");
final String shareBody = Title;
//I'm using Popcorn for Reddit, Are you? Get App from here:
Picasso.get().load(url).into(new Target() {
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("image/*");
i.putExtra(Intent.EXTRA_TEXT, shareBody);
i.putExtra(Intent.EXTRA_STREAM, getLocalBitmapUri(bitmap));
i.setType("image/jpeg");
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(i, "Share Image with..."));
}
@Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
} else {
showToast("Share Video Link");
String shareBody = Title + " \n\n" + url + " \n\n" + "Send via Popcorn for Reddit";
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("text/plain");
i.putExtra(Intent.EXTRA_TEXT, shareBody);
i.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(i, "Share Image with..."));
}
}
public Uri getLocalBitmapUri(Bitmap bmp) {
Uri bmpUri = null;
try {
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
bmpUri = Uri.fromFile(file);
} catch (IOException e) {
e.printStackTrace();
}
return bmpUri;
}
@SuppressLint("StaticFieldLeak")
private class ProgressBack extends AsyncTask<String,String,String> {
//ProgressDialog PD;
@Override
protected void onPreExecute() {
showToast("Downloading Video...");
}
@Override
protected String doInBackground(String... arg0) {
downloadVideo(arg0[0],"video_" + String.valueOf(System.currentTimeMillis()) + ".mpd");
return null;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
showToast("Download Complete");
}
}
private void downloadVideo(String fileURL, String fileName) {
try {
String rootDir = Environment.getExternalStorageDirectory()
+ File.separator + "Video" + File.separator + "Popcorn";
File rootFile = new File(rootDir);
rootFile.mkdir();
URL url = new URL(fileURL);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
FileOutputStream f = new FileOutputStream(new File(rootFile,
fileName));
InputStream in = c.getInputStream();
byte[] buffer = new byte[1024];
int len1;
while ((len1 = in.read(buffer)) > 0) {
f.write(buffer, 0, len1);
}
f.close();
} catch (IOException e) {
//showToast(e.getMessage());
Log.e("ERROR IN VIDEO",e.getMessage());
}
//showToast("Feature currently unavailable, Download using Browser!");
}
To know more about Android App development Subscribe to our weekly newsletter below.
Learn more about creating fancy button in Android Studio here.