package me.ccrama.redditslide.Adapters;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.support.v7.app.ActionBar;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import net.dean.jraw.http.NetworkException;
import net.dean.jraw.models.Submission;
import net.dean.jraw.paginators.DomainPaginator;
import net.dean.jraw.paginators.Paginator;
import net.dean.jraw.paginators.SubredditPaginator;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import me.ccrama.redditslide.Activities.BaseActivity;
import me.ccrama.redditslide.Activities.MainActivity;
import me.ccrama.redditslide.Activities.SubredditView;
import me.ccrama.redditslide.Authentication;
import me.ccrama.redditslide.BuildConfig;
import me.ccrama.redditslide.Constants;
import me.ccrama.redditslide.ContentType;
import me.ccrama.redditslide.Fragments.SubmissionsView;
import me.ccrama.redditslide.HasSeen;
import me.ccrama.redditslide.LastComments;
import me.ccrama.redditslide.OfflineSubreddit;
import me.ccrama.redditslide.PostLoader;
import me.ccrama.redditslide.PostMatch;
import me.ccrama.redditslide.R;
import me.ccrama.redditslide.Reddit;
import me.ccrama.redditslide.SettingValues;
import me.ccrama.redditslide.SubmissionCache;
import me.ccrama.redditslide.Synccit.MySynccitReadTask;
import me.ccrama.redditslide.TimeUtils;
import me.ccrama.redditslide.util.LogUtil;
import me.ccrama.redditslide.util.NetworkUtil;
/**
* This class is reponsible for loading subreddit specific submissions {@link loadMore(Context,
* SubmissionDisplay, boolean, String)} is implemented asynchronously. <p/> Created by ccrama on
* 9/17/2015.
*/
public class SubredditPosts implements PostLoader {
public List<Submission> posts;
public String subreddit;
public String subredditRandom;
public boolean nomore = false;
public boolean offline;
public boolean forced;
public boolean loading;
private Paginator paginator;
public OfflineSubreddit cached;
Context c;
boolean force18;
public SubredditPosts(String subreddit, Context c) {
posts = new ArrayList<>();
this.subreddit = subreddit;
this.c = c;
}
public SubredditPosts(String subreddit, Context c, boolean force18) {
posts = new ArrayList<>();
this.subreddit = subreddit;
this.c = c;
this.force18 = force18;
}
@Override
public void loadMore(final Context context, final SubmissionDisplay display,
final boolean reset) {
new LoadData(context, display, reset).execute(subreddit);
}
public void loadMore(Context context, SubmissionDisplay display, boolean reset,
String subreddit) {
this.subreddit = subreddit;
loadMore(context, display, reset);
}
public void loadPhotos(List<Submission> submissions) {
for (Submission submission : submissions) {
String url;
ContentType.Type type = ContentType.getContentType(submission);
if (submission.getThumbnails() != null) {
if (type == ContentType.Type.IMAGE
|| type == ContentType.Type.SELF
|| (submission.getThumbnailType() == Submission.ThumbnailType.URL)) {
if (type == ContentType.Type.IMAGE) {
if (((!NetworkUtil.isConnectedWifi(c) && SettingValues.lowResMobile)
|| SettingValues.lowResAlways)
&& submission.getThumbnails() != null
&& submission.getThumbnails().getVariations() != null
&& submission.getThumbnails().getVariations().length > 0) {
int length = submission.getThumbnails().getVariations().length;
if (SettingValues.lqLow && length >= 3) {
url = Html.fromHtml(
submission.getThumbnails().getVariations()[2].getUrl())
.toString(); //unescape url characters
} else if (SettingValues.lqMid && length >= 4) {
url = Html.fromHtml(
submission.getThumbnails().getVariations()[3].getUrl())
.toString(); //unescape url characters
} else if (length >= 5) {
url = Html.fromHtml(submission.getThumbnails().getVariations()[
length
- 1].getUrl()).toString(); //unescape url characters
} else {
url = Html.fromHtml(submission.getThumbnails().getSource().getUrl())
.toString(); //unescape url characters
}
} else {
if (submission.getDataNode().has("preview") && submission.getDataNode()
.get("preview")
.get("images")
.get(0)
.get("source")
.has("height")) { //Load the preview image which has probably already been cached in memory instead of the direct link
url = submission.getDataNode()
.get("preview")
.get("images")
.get(0)
.get("source")
.get("url")
.asText();
} else {
url = submission.getUrl();
}
}
((Reddit) c.getApplicationContext()).getImageLoader()
.loadImage(url, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage) {
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
});
} else if (submission.getThumbnails() != null) {
if (((!NetworkUtil.isConnectedWifi(c) && SettingValues.lowResMobile)
|| SettingValues.lowResAlways)
&& submission.getThumbnails().getVariations().length != 0) {
int length = submission.getThumbnails().getVariations().length;
if (SettingValues.lqLow && length >= 3) {
url = Html.fromHtml(
submission.getThumbnails().getVariations()[2].getUrl())
.toString(); //unescape url characters
} else if (SettingValues.lqMid && length >= 4) {
url = Html.fromHtml(
submission.getThumbnails().getVariations()[3].getUrl())
.toString(); //unescape url characters
} else if (length >= 5) {
url = Html.fromHtml(submission.getThumbnails().getVariations()[
length
- 1].getUrl()).toString(); //unescape url characters
} else {
url = Html.fromHtml(submission.getThumbnails().getSource().getUrl())
.toString(); //unescape url characters
}
} else {
url = Html.fromHtml(submission.getThumbnails().getSource().getUrl())
.toString(); //unescape url characters
}
((Reddit) c.getApplicationContext()).getImageLoader()
.loadImage(url, new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage) {
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
});
} else if (submission.getThumbnail() != null && (submission.getThumbnailType()
== Submission.ThumbnailType.URL
|| submission.getThumbnailType() == Submission.ThumbnailType.NSFW)) {
((Reddit) c.getApplicationContext()).getImageLoader()
.loadImage(submission.getUrl(), new ImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
}
@Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage) {
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
});
}
}
}
}
}
public ArrayList<String> all;
@Override
public List<Submission> getPosts() {
return posts;
}
@Override
public boolean hasMore() {
return !nomore;
}
public boolean skipOne;
boolean usedOffline;
public long currentid;
public SubmissionDisplay displayer;
/**
* Asynchronous task for loading data
*/
private class LoadData extends AsyncTask<String, Void, List<Submission>> {
final boolean reset;
Context context;
public LoadData(Context context, SubmissionDisplay display, boolean reset) {
this.context = context;
displayer = display;
this.reset = reset;
}
public int start;
@Override
public void onPostExecute(final List<Submission> submissions) {
loading = false;
if (error != null) {
if (error instanceof NetworkException) {
NetworkException e = (NetworkException) error;
Toast.makeText(context, "Loading failed, " + e.getResponse().getStatusCode() + (
e.getResponse().getStatusMessage().isEmpty() ? ""
: ": " + e.getResponse().getStatusMessage()),
Toast.LENGTH_SHORT).show();
}
if (error.getCause() instanceof UnknownHostException) {
Toast.makeText(context, "Loading failed, please check your internet connection",
Toast.LENGTH_LONG).show();
}
displayer.updateError();
} else if (submissions != null && !submissions.isEmpty()) {
if (displayer instanceof SubmissionsView
&& ((SubmissionsView) displayer).adapter.isError) {
((SubmissionsView) displayer).adapter.undoSetError();
}
String[] ids = new String[submissions.size()];
int i = 0;
for (Submission s : submissions) {
ids[i] = s.getId();
i++;
}
// update online
displayer.updateSuccess(posts, start);
currentid = 0;
OfflineSubreddit.currentid = currentid;
if (c instanceof BaseActivity) {
((BaseActivity) c).setShareUrl("https://reddit.com/r/" + subreddit);
}
if (subreddit.equals("random") || subreddit.equals("myrandom") || subreddit.equals(
"randnsfw")) {
subredditRandom = submissions.get(0).getSubredditName();
}
MainActivity.randomoverride = subredditRandom;
if (context instanceof SubredditView && (subreddit.equals("random")
|| subreddit.equals("myrandom")
|| subreddit.equals("randnsfw"))) {
((SubredditView) context).subreddit = subredditRandom;
((SubredditView) context).executeAsyncSubreddit(subredditRandom);
}
if (!SettingValues.synccitName.isEmpty() && !offline) {
new MySynccitReadTask(displayer).execute(ids);
}
} else if (submissions != null) {
// end of submissions
nomore = true;
displayer.updateSuccess(posts, posts.size() + 1);
} else if (MainActivity.isRestart) {
posts = new ArrayList<>();
cached = OfflineSubreddit.getSubreddit(subreddit, 0L, true, c);
for (Submission s : cached.submissions) {
if (!PostMatch.doesMatch(s, subreddit, force18)) {
posts.add(s);
}
}
offline = false;
usedOffline = false;
displayer.updateSuccess(posts, start);
} else {
if (!all.isEmpty() && !nomore && SettingValues.cache) {
if (context instanceof MainActivity) {
doMainActivityOffline(context, displayer);
}
} else if (!nomore) {
// error
LogUtil.v("Setting error");
displayer.updateError();
}
}
}
@Override
protected List<Submission> doInBackground(String... subredditPaginators) {
if (BuildConfig.DEBUG) LogUtil.v("Loading data");
if ((!NetworkUtil.isConnected(context) && !Authentication.didOnline)
|| MainActivity.isRestart) {
Log.v(LogUtil.getTag(), "Using offline data");
offline = true;
usedOffline = true;
all = OfflineSubreddit.getAll(subreddit);
return null;
} else {
offline = false;
usedOffline = false;
}
if (reset || paginator == null) {
offline = false;
nomore = false;
String sub = subredditPaginators[0].toLowerCase();
if ((sub.equals("random") || sub.equals("randnsfw"))
&& MainActivity.randomoverride != null
&& !MainActivity.randomoverride.isEmpty()) {
sub = MainActivity.randomoverride;
MainActivity.randomoverride = "";
}
if (sub.equals("frontpage")) {
paginator = new SubredditPaginator(Authentication.reddit);
} else if (!sub.contains(".")) {
paginator = new SubredditPaginator(Authentication.reddit, sub);
} else {
paginator = new DomainPaginator(Authentication.reddit, sub);
}
paginator.setSorting(SettingValues.getSubmissionSort(subreddit));
paginator.setTimePeriod(SettingValues.getSubmissionTimePeriod(subreddit));
paginator.setLimit(Constants.PAGINATOR_POST_LIMIT);
}
List<Submission> filteredSubmissions = getNextFiltered();
if (!(SettingValues.noImages && ((!NetworkUtil.isConnectedWifi(c)
&& SettingValues.lowResMobile) || SettingValues.lowResAlways))) {
loadPhotos(filteredSubmissions);
}
if (SettingValues.storeHistory) {
HasSeen.setHasSeenSubmission(filteredSubmissions);
LastComments.setCommentsSince(filteredSubmissions);
}
SubmissionCache.cacheSubmissions(filteredSubmissions, context, subreddit);
if (reset || offline || posts == null) {
posts = new ArrayList<>(new LinkedHashSet(filteredSubmissions));
start = -1;
} else {
posts.addAll(filteredSubmissions);
posts = new ArrayList<>(new LinkedHashSet(posts));
offline = false;
}
if (!usedOffline) {
OfflineSubreddit.getSubNoLoad(subreddit.toLowerCase())
.overwriteSubmissions(posts)
.writeToMemory(context);
}
start = 0;
if (posts != null) {
start = posts.size() + 1;
}
return filteredSubmissions;
}
public ArrayList<Submission> getNextFiltered() {
ArrayList<Submission> filteredSubmissions = new ArrayList<>();
ArrayList<Submission> adding = new ArrayList<>();
try {
if (paginator != null && paginator.hasNext()) {
if (force18 && paginator instanceof SubredditPaginator) {
((SubredditPaginator) paginator).setObeyOver18(false);
}
adding.addAll(paginator.next());
} else {
nomore = true;
}
for (Submission s : adding) {
if (!PostMatch.doesMatch(s, paginator instanceof SubredditPaginator
? ((SubredditPaginator) paginator).getSubreddit()
: ((DomainPaginator) paginator).getDomain(), force18)) {
filteredSubmissions.add(s);
}
}
if (paginator != null && paginator.hasNext() && filteredSubmissions.isEmpty()) {
filteredSubmissions.addAll(getNextFiltered());
}
} catch (Exception e) {
e.printStackTrace();
error = e;
if (e.getMessage() != null && e.getMessage().contains("Forbidden")) {
Reddit.authentication.updateToken(context);
}
}
return filteredSubmissions;
}
Exception error;
}
public void doMainActivityOffline(final Context c, final SubmissionDisplay displayer) {
LogUtil.v(subreddit);
if (all == null) {
all = OfflineSubreddit.getAll(subreddit);
}
Collections.rotate(all, -1); //Move 0, or "submission only", to the end
offline = true;
final String[] titles = new String[all.size()];
final String[] base = new String[all.size()];
int i = 0;
for (String s : all) {
String[] split = s.split(",");
titles[i] = (Long.valueOf(split[1]) == 0 ? c.getString(
R.string.settings_backup_submission_only)
: TimeUtils.getTimeAgo(Long.valueOf(split[1]), c) + c.getString(
R.string.settings_backup_comments));
base[i] = s;
i++;
}
((MainActivity) c).getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
((MainActivity) c).getSupportActionBar()
.setListNavigationCallbacks(
new OfflineSubAdapter(c, android.R.layout.simple_list_item_1, titles),
new ActionBar.OnNavigationListener() {
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
final String[] s2 = base[itemPosition].split(",");
OfflineSubreddit.currentid = Long.valueOf(s2[1]);
currentid = OfflineSubreddit.currentid;
new AsyncTask<Void, Void, Void>() {
OfflineSubreddit cached;
@Override
protected Void doInBackground(Void... params) {
cached = OfflineSubreddit.getSubreddit(subreddit,
Long.valueOf(s2[1]), true, c);
List<Submission> finalSubs = new ArrayList<>();
for (Submission s : cached.submissions) {
if (!PostMatch.doesMatch(s, subreddit, force18)) {
finalSubs.add(s);
}
}
posts = finalSubs;
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
if (cached.submissions.isEmpty()) {
displayer.updateOfflineError();
}
// update offline
displayer.updateOffline(posts, Long.valueOf(s2[1]));
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
return true;
}
});
}
}