Add generic login/out support.

Use getters and setters for the mutable fields of Post.
Use HttpUrl for all endpoints.
multisite
Floens 9 years ago
parent f8c182bba5
commit 9f462aa416
  1. 16
      Clover/app/src/main/java/org/floens/chan/chan/ChanLoader.java
  2. 12
      Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java
  3. 4
      Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java
  4. 1
      Clover/app/src/main/java/org/floens/chan/core/model/Board.java
  5. 118
      Clover/app/src/main/java/org/floens/chan/core/model/Post.java
  6. 14
      Clover/app/src/main/java/org/floens/chan/core/model/PostImage.java
  7. 2
      Clover/app/src/main/java/org/floens/chan/core/presenter/ImageViewerPresenter.java
  8. 10
      Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java
  9. 5
      Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java
  10. 2
      Clover/app/src/main/java/org/floens/chan/core/saver/ImageSaveTask.java
  11. 28
      Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
  12. 18
      Clover/app/src/main/java/org/floens/chan/core/site/Site.java
  13. 22
      Clover/app/src/main/java/org/floens/chan/core/site/SiteEndpoints.java
  14. 31
      Clover/app/src/main/java/org/floens/chan/core/site/SiteRequestModifier.java
  15. 7
      Clover/app/src/main/java/org/floens/chan/core/site/Sites.java
  16. 5
      Clover/app/src/main/java/org/floens/chan/core/site/http/DeleteRequest.java
  17. 7
      Clover/app/src/main/java/org/floens/chan/core/site/http/HttpCall.java
  18. 6
      Clover/app/src/main/java/org/floens/chan/core/site/http/HttpCallManager.java
  19. 6
      Clover/app/src/main/java/org/floens/chan/core/site/http/LoginRequest.java
  20. 4
      Clover/app/src/main/java/org/floens/chan/core/site/http/Reply.java
  21. 209
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java
  22. 2
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4BoardsRequest.java
  23. 6
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4DeleteHttpCall.java
  24. 6
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4PassHttpCall.java
  25. 10
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReaderRequest.java
  26. 10
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReplyHttpCall.java
  27. 2
      Clover/app/src/main/java/org/floens/chan/test/TestActivity.java
  28. 4
      Clover/app/src/main/java/org/floens/chan/ui/adapter/PostsFilter.java
  29. 2
      Clover/app/src/main/java/org/floens/chan/ui/cell/CardPostCell.java
  30. 17
      Clover/app/src/main/java/org/floens/chan/ui/cell/PostCell.java
  31. 11
      Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java
  32. 10
      Clover/app/src/main/java/org/floens/chan/ui/controller/ImageViewerController.java
  33. 5
      Clover/app/src/main/java/org/floens/chan/ui/controller/MainSettingsController.java
  34. 28
      Clover/app/src/main/java/org/floens/chan/ui/controller/PassSettingsController.java
  35. 24
      Clover/app/src/main/java/org/floens/chan/ui/controller/ReportController.java
  36. 6
      Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java
  37. 8
      Clover/app/src/main/java/org/floens/chan/ui/view/MultiImageView.java
  38. 2
      Clover/app/src/main/java/org/floens/chan/ui/view/PostImageThumbnailView.java
  39. 4
      Clover/app/src/main/java/org/floens/chan/utils/AndroidUtils.java

@ -265,7 +265,7 @@ public class ChanLoader implements Response.ErrorListener, Response.Listener<Cha
}
for (Post post : thread.posts) {
post.title = loadable.title;
post.setTitle(loadable.title);
}
lastLoadTime = Time.get();
@ -296,12 +296,14 @@ public class ChanLoader implements Response.ErrorListener, Response.Listener<Cha
thread.op = realOp;
Post.Builder fakeOp = response.op;
if (fakeOp != null) {
thread.closed = realOp.closed = fakeOp.closed;
thread.archived = realOp.archived = fakeOp.archived;
realOp.sticky = fakeOp.sticky;
realOp.replies = fakeOp.replies;
realOp.images = fakeOp.images;
realOp.uniqueIps = fakeOp.uniqueIps;
realOp.setClosed(fakeOp.closed);
thread.closed = realOp.isClosed();
realOp.setArchived(fakeOp.archived);
thread.archived = realOp.isArchived();
realOp.setSticky(fakeOp.sticky);
realOp.setReplies(fakeOp.replies);
realOp.setImages(fakeOp.images);
realOp.setUniqueIps(fakeOp.uniqueIps);
} else {
Logger.e(TAG, "Thread has no op!");
}

@ -40,18 +40,6 @@ public class ChanUrls {
return scheme() + "://boards.4chan.org/" + board + "/catalog";
}
public static String getPassUrl() {
return "https://sys.4chan.org/auth";
}
public static String[] getReportCookies(String passId) {
return new String[]{"pass_enabled=1;", "pass_id=" + passId + ";"};
}
public static String getReportUrl(String board, int no) {
return "https://sys.4chan.org/" + board + "/imgboard.php?mode=report&no=" + no;
}
private static String scheme() {
return ChanSettings.networkHttps.get() ? "https" : "http";
}

@ -162,7 +162,7 @@ public class WatchManager {
pin.loadable = loadable;
pin.loadable.title = PostHelper.getTitle(opPost, loadable);
PostImage image = opPost.image;
pin.thumbnailUrl = image == null ? "" : image.thumbnailUrl;
pin.thumbnailUrl = image == null ? "" : image.thumbnailUrl.toString();
return createPin(pin);
}
@ -746,7 +746,7 @@ public class WatchManager {
pin.isError = false;
if (pin.thumbnailUrl == null && thread.op != null && thread.op.image != null) {
pin.thumbnailUrl = thread.op.image.thumbnailUrl;
pin.thumbnailUrl = thread.op.image.thumbnailUrl.toString();
}
// Populate posts list

@ -67,6 +67,7 @@ public class Board implements SiteReference {
// named value for legacy support
@DatabaseField(columnName = "value")
// TODO(sec) force filter this to ascii & numbers.
public String code;
@DatabaseField

@ -17,6 +17,8 @@
*/
package org.floens.chan.core.model;
import android.support.annotation.MainThread;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@ -24,6 +26,8 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import okhttp3.HttpUrl;
/**
* Contains all data needed to represent a single post.<br>
* All {@code final} fields are thread-safe.
@ -45,6 +49,11 @@ public class Post {
public final String subject;
/**
* Unix timestamp, in seconds.
*/
public final long time;
public final PostImage image;
public final String tripcode;
@ -57,12 +66,7 @@ public class Post {
public final String countryName;
/**
* Unix timestamp, in seconds.
*/
public final long time;
public final String countryUrl;
public final HttpUrl countryUrl;
public final boolean isSavedReply;
@ -83,24 +87,28 @@ public class Post {
public final CharSequence nameTripcodeIdCapcodeSpan;
// These members may only mutate on the main thread.
public boolean sticky = false;
public boolean closed = false;
public boolean archived = false;
public int replies = -1;
public int images = -1;
public int uniqueIps = 1;
public String title = "";
// Atomic, any thread.
/**
* This post has been deleted (the server isn't sending it anymore).
* <p><b>This boolean is modified in worker threads, use {@code .get()} to access it.</b>
*/
public final AtomicBoolean deleted = new AtomicBoolean(false);
/**
* These ids replied to this post.<br>
* <b>synchronize on this when accessing.</b>
* These ids replied to this post.
* <p><b>Manual synchronization is needed, since this list can be modified from any thread.
* Wrap all accesses in a {@code synchronized} block.</b>
*/
public final List<Integer> repliesFrom = new ArrayList<>();
// These members may only mutate on the main thread.
private boolean sticky = false;
private boolean closed = false;
private boolean archived = false;
private int replies = -1;
private int images = -1;
private int uniqueIps = 1;
private String title = "";
private Post(Builder builder) {
board = builder.board;
boardId = builder.board.code;
@ -142,6 +150,76 @@ public class Post {
repliesTo = Collections.unmodifiableSet(builder.repliesToIds);
}
@MainThread
public boolean isSticky() {
return sticky;
}
@MainThread
public void setSticky(boolean sticky) {
this.sticky = sticky;
}
@MainThread
public boolean isClosed() {
return closed;
}
@MainThread
public void setClosed(boolean closed) {
this.closed = closed;
}
@MainThread
public boolean isArchived() {
return archived;
}
@MainThread
public void setArchived(boolean archived) {
this.archived = archived;
}
@MainThread
public int getReplies() {
return replies;
}
@MainThread
public void setReplies(int replies) {
this.replies = replies;
}
@MainThread
public int getImages() {
return images;
}
@MainThread
public void setImages(int images) {
this.images = images;
}
@MainThread
public int getUniqueIps() {
return uniqueIps;
}
@MainThread
public void setUniqueIps(int uniqueIps) {
this.uniqueIps = uniqueIps;
}
@MainThread
public String getTitle() {
return title;
}
@MainThread
public void setTitle(String title) {
this.title = title;
}
public static final class Builder {
public Board board;
public int id = -1;
@ -165,7 +243,7 @@ public class Post {
public String countryCode;
public String countryName;
public String countryUrl;
public HttpUrl countryUrl;
public String posterId = "";
public String moderatorCapcode = "";
@ -275,7 +353,7 @@ public class Post {
return this;
}
public Builder country(String countryCode, String countryName, String countryUrl) {
public Builder country(String countryCode, String countryName, HttpUrl countryUrl) {
this.countryCode = countryCode;
this.countryName = countryName;
this.countryUrl = countryUrl;

@ -19,14 +19,16 @@ package org.floens.chan.core.model;
import org.floens.chan.core.settings.ChanSettings;
import okhttp3.HttpUrl;
public class PostImage {
public enum Type {
STATIC, GIF, MOVIE
}
public final String originalName;
public final String thumbnailUrl;
public final String imageUrl;
public final HttpUrl thumbnailUrl;
public final HttpUrl imageUrl;
public final String filename;
public final String extension;
public final int imageWidth;
@ -62,8 +64,8 @@ public class PostImage {
public static final class Builder {
private String originalName;
private String thumbnailUrl;
private String imageUrl;
private HttpUrl thumbnailUrl;
private HttpUrl imageUrl;
private String filename;
private String extension;
private int imageWidth;
@ -79,12 +81,12 @@ public class PostImage {
return this;
}
public Builder thumbnailUrl(String thumbnailUrl) {
public Builder thumbnailUrl(HttpUrl thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
return this;
}
public Builder imageUrl(String imageUrl) {
public Builder imageUrl(HttpUrl imageUrl) {
this.imageUrl = imageUrl;
return this;
}

@ -271,7 +271,7 @@ public class ImageViewerPresenter implements MultiImageView.Callback, ViewPager.
private boolean imageAutoLoad(PostImage postImage) {
// Auto load the image when it is cached
return fileCache.exists(postImage.imageUrl) || shouldLoadForNetworkType(ChanSettings.imageAutoLoadNetwork.get());
return fileCache.exists(postImage.imageUrl.toString()) || shouldLoadForNetworkType(ChanSettings.imageAutoLoadNetwork.get());
}
private boolean videoAutoLoad(PostImage postImage) {

@ -197,18 +197,10 @@ public class ReplyPresenter implements CaptchaCallback, ImagePickDelegate.ImageP
callback.loadViewsIntoDraft(draft);
draft.loadable = loadable;
if (ChanSettings.passLoggedIn()) {
draft.noVerification = true;
draft.passId = ChanSettings.passId.get();
} else {
draft.noVerification = false;
draft.passId = null;
}
draft.spoilerImage = draft.spoilerImage && board.spoilers;
draft.captchaResponse = null;
if (draft.noVerification) {
if (loadable.getSite().isLoggedIn()) {
makeSubmitCall();
} else {
switchPage(Page.CAPTCHA, true);

@ -612,7 +612,8 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
databaseManager.getDatabaseSavedReplyManager().findSavedReply(post.boardId, post.no)
);
if (reply != null) {
loadable.getSite().delete(new DeleteRequest(loadable.getSite(), post, reply, onlyImageDelete), new Site.DeleteListener() {
Site site = loadable.getSite();
site.delete(new DeleteRequest(post, reply, onlyImageDelete), new Site.DeleteListener() {
@Override
public void onDeleteComplete(HttpCall httpPost, DeleteResponse deleteResponse) {
String message;
@ -698,7 +699,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
History history = new History();
history.loadable = loadable;
PostImage image = chanLoader.getThread().op.image;
history.thumbnailUrl = image == null ? "" : image.thumbnailUrl;
history.thumbnailUrl = image == null ? "" : image.thumbnailUrl.toString();
databaseManager.getDatabaseHistoryManager().add(history);
}
}

@ -118,7 +118,7 @@ public class ImageSaveTask implements Runnable, FileCache.DownloadedCallback {
if (destination.exists()) {
onDestination();
} else {
FileCache.FileCacheDownloader fileCacheDownloader = fileCache.downloadFile(postImage.imageUrl, this);
FileCache.FileCacheDownloader fileCacheDownloader = fileCache.downloadFile(postImage.imageUrl.toString(), this);
// If the fileCacheDownloader is null then the destination already existed and onSuccess() has been called.
// Wait otherwise for the download to finish to avoid that the next task is immediately executed.
if (fileCacheDownloader != null) {

@ -141,10 +141,6 @@ public class ChanSettings {
public static final BooleanSetting watchPeek;
public static final StringSetting watchLed;
public static final StringSetting passToken;
public static final StringSetting passPin;
public static final StringSetting passId;
public static final BooleanSetting historyEnabled;
public static final IntegerSetting previousVersion;
@ -158,22 +154,6 @@ public class ChanSettings {
public static final CounterSetting replyOpenCounter;
public static final CounterSetting threadOpenCounter;
public enum TestOptions implements OptionSettingItem {
ONE("one"),
TWO("two"),
THREE("three");
String name;
TestOptions(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
static {
SharedPreferences p = AndroidUtils.getPreferences();
@ -251,10 +231,6 @@ public class ChanSettings {
watchPeek = new BooleanSetting(p, "preference_watch_peek", true);
watchLed = new StringSetting(p, "preference_watch_led", "ffffffff");
passToken = new StringSetting(p, "preference_pass_token", "");
passPin = new StringSetting(p, "preference_pass_pin", "");
passId = new StringSetting(p, "preference_pass_id", "");
historyEnabled = new BooleanSetting(p, "preference_history_enabled", true);
previousVersion = new IntegerSetting(p, "preference_previous_version", 0);
@ -295,10 +271,6 @@ public class ChanSettings {
// preference_watch_background_timeout "60" the old timeout background setting in minutes
}
public static boolean passLoggedIn() {
return passId.get().length() > 0;
}
public static ThemeColor getThemeAndColor() {
String themeRaw = ChanSettings.theme.get();

@ -17,6 +17,8 @@
*/
package org.floens.chan.core.site;
import android.support.annotation.Nullable;
import org.floens.chan.chan.ChanLoaderRequest;
import org.floens.chan.chan.ChanLoaderRequestParams;
import org.floens.chan.core.model.Board;
@ -56,7 +58,7 @@ public interface Site {
POST_REPORT,
/**
* This site supports some sort of login (like 4pass).
* This site supports some sort of authentication (like 4pass).
*
* @see #login(LoginRequest, LoginListener)
* @see SiteEndpoints#login()
@ -113,8 +115,12 @@ public interface Site {
SiteEndpoints endpoints();
SiteRequestModifier requestModifier();
BoardsType boardsType();
String desktopUrl(Loadable loadable, @Nullable Post post);
void boards(BoardsListener boardsListener);
interface BoardsListener {
@ -141,8 +147,18 @@ public interface Site {
void onDeleteError(HttpCall httpCall);
}
/* TODO(multi-site) this login mechanism is probably not generic enough right now,
* especially if we're thinking about what a login really is
* We'll expand this later when we have a better idea of what other sites require.
*/
void login(LoginRequest loginRequest, LoginListener loginListener);
void logout();
boolean isLoggedIn();
LoginRequest getLoginDetails();
interface LoginListener {
void onLoginComplete(HttpCall httpCall, LoginResponse loginResponse);

@ -23,27 +23,29 @@ import org.floens.chan.core.model.Post;
import java.util.Map;
import okhttp3.HttpUrl;
/**
* Endpoints for {@link Site}.
*/
public interface SiteEndpoints {
String catalog(Board board);
HttpUrl catalog(Board board);
String thread(Board board, Loadable loadable);
HttpUrl thread(Board board, Loadable loadable);
String imageUrl(Post.Builder post, Map<String, String> arg);
HttpUrl imageUrl(Post.Builder post, Map<String, String> arg);
String thumbnailUrl(Post.Builder post, boolean spoiler, Map<String, String> arg);
HttpUrl thumbnailUrl(Post.Builder post, boolean spoiler, Map<String, String> arg);
String flag(Post.Builder post, String countryCode, Map<String, String> arg);
HttpUrl flag(Post.Builder post, String countryCode, Map<String, String> arg);
String boards();
HttpUrl boards();
String reply(Loadable thread);
HttpUrl reply(Loadable thread);
String delete(Post post);
HttpUrl delete(Post post);
String report(Post post);
HttpUrl report(Post post);
String login();
HttpUrl login();
}

@ -0,0 +1,31 @@
/*
* Clover - 4chan browser https://github.com/Floens/Clover/
* Copyright (C) 2014 Floens
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.floens.chan.core.site;
import android.webkit.WebView;
import org.floens.chan.core.site.http.HttpCall;
import okhttp3.Request;
public interface SiteRequestModifier {
void modifyHttpCall(HttpCall httpCall, Request.Builder requestBuilder);
void modifyWebView(WebView webView);
}

@ -1,6 +1,9 @@
package org.floens.chan.core.site;
import android.content.SharedPreferences;
import org.floens.chan.core.site.sites.chan4.Chan4;
import org.floens.chan.utils.AndroidUtils;
import java.util.Arrays;
import java.util.List;
@ -34,4 +37,8 @@ public class Sites {
public static Site defaultSite() {
return CHAN4;
}
public static SharedPreferences getPreferences(Site site) {
return AndroidUtils.getPreferences(site.id() + "_site_preferences");
}
}

@ -20,16 +20,13 @@ package org.floens.chan.core.site.http;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.SavedReply;
import org.floens.chan.core.site.Site;
public class DeleteRequest {
public final Site site;
public final Post post;
public final SavedReply savedReply;
public final boolean imageOnly;
public DeleteRequest(Site site, Post post, SavedReply savedReply, boolean imageOnly) {
this.site = site;
public DeleteRequest(Post post, SavedReply savedReply, boolean imageOnly) {
this.post = post;
this.savedReply = savedReply;
this.imageOnly = imageOnly;

@ -17,6 +17,7 @@
*/
package org.floens.chan.core.site.http;
import org.floens.chan.core.site.Site;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.IOUtils;
import org.floens.chan.utils.Logger;
@ -38,6 +39,8 @@ import okhttp3.Response;
public abstract class HttpCall implements Callback {
private static final String TAG = "HttpCall";
protected Site site;
private boolean successful = false;
private HttpCallback callback;
private Exception exception;
@ -46,6 +49,10 @@ public abstract class HttpCall implements Callback {
public abstract void process(Response response, String result) throws IOException;
public HttpCall(Site site) {
this.site = site;
}
@Override
public void onResponse(Call call, Response response) {
try {

@ -19,6 +19,7 @@ package org.floens.chan.core.site.http;
import org.floens.chan.core.di.UserAgentProvider;
import org.floens.chan.core.site.Site;
import java.util.concurrent.TimeUnit;
@ -53,8 +54,13 @@ public class HttpCallManager {
Request.Builder requestBuilder = new Request.Builder();
Site site = httpCall.site;
httpCall.setup(requestBuilder);
if (site != null) {
site.requestModifier().modifyHttpCall(httpCall, requestBuilder);
}
requestBuilder.header("User-Agent", userAgentProvider.getUserAgent());
Request request = requestBuilder.build();

@ -18,15 +18,11 @@
package org.floens.chan.core.site.http;
import org.floens.chan.core.site.Site;
public class LoginRequest {
public final Site site;
public final String user;
public final String pass;
public LoginRequest(Site site, String user, String pass) {
this.site = site;
public LoginRequest(String user, String pass) {
this.user = user;
this.pass = pass;
}

@ -35,12 +35,8 @@ public class Reply {
*/
public String captchaResponse;
// TODO(multi-site) flip boolean
public boolean noVerification = false;
public Loadable loadable;
public String passId;
public File file;
public String fileName = "";
public String name = "";

@ -17,6 +17,11 @@
*/
package org.floens.chan.core.site.sites.chan4;
import android.content.SharedPreferences;
import android.support.annotation.Nullable;
import android.webkit.CookieManager;
import android.webkit.WebView;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
@ -26,14 +31,18 @@ import org.floens.chan.chan.ChanLoaderRequestParams;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.settings.StringSetting;
import org.floens.chan.core.site.Boards;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.SiteEndpoints;
import org.floens.chan.core.site.SiteRequestModifier;
import org.floens.chan.core.site.http.DeleteRequest;
import org.floens.chan.core.site.http.HttpCall;
import org.floens.chan.core.site.http.HttpCallManager;
import org.floens.chan.core.site.http.LoginRequest;
import org.floens.chan.core.site.http.LoginResponse;
import org.floens.chan.core.site.http.Reply;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.Logger;
import java.util.ArrayList;
@ -45,6 +54,9 @@ import java.util.Random;
import javax.inject.Inject;
import okhttp3.HttpUrl;
import okhttp3.Request;
import static org.floens.chan.Chan.getGraph;
public class Chan4 implements Site {
@ -59,68 +71,171 @@ public class Chan4 implements Site {
RequestQueue requestQueue;
private final SiteEndpoints endpoints = new SiteEndpoints() {
private final HttpUrl a = new HttpUrl.Builder()
.scheme("https")
.host("a.4cdn.org")
.build();
private final HttpUrl i = new HttpUrl.Builder()
.scheme("https")
.host("i.4cdn.org")
.build();
private final HttpUrl t = new HttpUrl.Builder()
.scheme("https")
.host("t.4cdn.org")
.build();
private final HttpUrl s = new HttpUrl.Builder()
.scheme("https")
.host("s.4cdn.org")
.build();
private final HttpUrl sys = new HttpUrl.Builder()
.scheme("https")
.host("sys.4chan.org")
.build();
@Override
public String catalog(Board board) {
return "https://a.4cdn.org/" + board.code + "/catalog.json";
public HttpUrl catalog(Board board) {
return a.newBuilder()
.addPathSegment(board.code)
.addPathSegment("catalog.json")
.build();
}
@Override
public String thread(Board board, Loadable loadable) {
return "https://a.4cdn.org/" + board.code + "/thread/" + loadable.no + ".json";
public HttpUrl thread(Board board, Loadable loadable) {
return a.newBuilder()
.addPathSegment(board.code)
.addPathSegment("thread")
.addPathSegment(loadable.no + ".json")
.build();
}
@Override
public String imageUrl(Post.Builder post, Map<String, String> arg) {
return "https://i.4cdn.org/" + post.board.code + "/" + arg.get("tim") + "." + arg.get("ext");
public HttpUrl imageUrl(Post.Builder post, Map<String, String> arg) {
return i.newBuilder()
.addPathSegment(post.board.code)
.addPathSegment(arg.get("tim") + "." + arg.get("ext"))
.build();
}
@Override
public String thumbnailUrl(Post.Builder post, boolean spoiler, Map<String, String> arg) {
public HttpUrl thumbnailUrl(Post.Builder post, boolean spoiler, Map<String, String> arg) {
if (spoiler) {
HttpUrl.Builder image = s.newBuilder()
.addPathSegment("image");
if (post.board.customSpoilers >= 0) {
int i = random.nextInt(post.board.customSpoilers) + 1;
return "https://s.4cdn.org/image/spoiler-" + post.board.code + i + ".png";
image.addPathSegment("spoiler-" + post.board.code + i + ".png");
} else {
return "https://s.4cdn.org/image/spoiler.png";
image.addPathSegment("spoiler.png");
}
return image.build();
} else {
return "https://t.4cdn.org/" + post.board.code + "/" + arg.get("tim") + "s.jpg";
return t.newBuilder()
.addPathSegment(post.board.code)
.addPathSegment(arg.get("tim") + "s.jpg")
.build();
}
}
@Override
public String flag(Post.Builder post, String countryCode, Map<String, String> arg) {
return "https://s.4cdn.org/image/country/" + countryCode.toLowerCase(Locale.ENGLISH) + ".gif";
public HttpUrl flag(Post.Builder post, String countryCode, Map<String, String> arg) {
return s.newBuilder()
.addPathSegment("image")
.addPathSegment("country")
.addPathSegment(countryCode.toLowerCase(Locale.ENGLISH) + ".gif")
.build();
}
@Override
public String boards() {
return "https://a.4cdn.org/boards.json";
public HttpUrl boards() {
return a.newBuilder()
.addPathSegment("boards.json")
.build();
}
@Override
public String reply(Loadable loadable) {
return "https://sys.4chan.org/" + loadable.getBoard().code + "/post";
public HttpUrl reply(Loadable loadable) {
return sys.newBuilder()
.addPathSegment(loadable.board.code)
.addPathSegment("post")
.build();
}
@Override
public String delete(Post post) {
return "https://sys.4chan.org/" + post.board.code + "/imgboard.php";
public HttpUrl delete(Post post) {
return sys.newBuilder()
.addPathSegment(post.board.code)
.addPathSegment("imgboard.php")
.build();
}
@Override
public String report(Post post) {
return "https://sys.4chan.org/" + post.board.code + "/imgboard.php?mode=report&no=" + post.no;
public HttpUrl report(Post post) {
return sys.newBuilder()
.addPathSegment(post.board.code)
.addPathSegment("imgboard.php")
.addQueryParameter("mode", "report")
.addQueryParameter("no", String.valueOf(post.no))
.build();
}
@Override
public String login() {
return "https://sys.4chan.org/auth";
public HttpUrl login() {
return sys.newBuilder()
.addPathSegment("auth")
.build();
}
};
private SiteRequestModifier siteRequestModifier = new SiteRequestModifier() {
@Override
public void modifyHttpCall(HttpCall httpCall, Request.Builder requestBuilder) {
if (isLoggedIn()) {
requestBuilder.addHeader("Cookie", "pass_id=" + passToken.get());
}
}
@SuppressWarnings("deprecation")
@Override
public void modifyWebView(WebView webView) {
final HttpUrl sys = new HttpUrl.Builder()
.scheme("https")
.host("sys.4chan.org")
.build();
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
if (isLoggedIn()) {
String[] passCookies = {
"pass_enabled=1;",
"pass_id=" + passToken.get() + ";"
};
String domain = sys.scheme() + "://" + sys.host() + "/";
for (String cookie : passCookies) {
cookieManager.setCookie(domain, cookie);
}
}
}
};
// Legacy settings that were global before
private final StringSetting passUser;
private final StringSetting passPass;
private final StringSetting passToken;
public Chan4() {
getGraph().inject(this);
SharedPreferences p = AndroidUtils.getPreferences();
passUser = new StringSetting(p, "preference_pass_token", "");
passPass = new StringSetting(p, "preference_pass_pin", "");
// token was renamed, before it meant the username, now it means the token returned
// from the server that the cookie is set to.
passToken = new StringSetting(p, "preference_pass_id", "");
}
/**
@ -160,6 +275,21 @@ public class Chan4 implements Site {
return BoardsType.DYNAMIC;
}
@Override
public String desktopUrl(Loadable loadable, @Nullable Post post) {
if (loadable.isCatalogMode()) {
return "https://boards.4chan.org/" + loadable.board.code + "/";
} else if (loadable.isThreadMode()) {
String url = "https://boards.4chan.org/" + loadable.board.code + "/thread/" + loadable.no;
if (post != null) {
url += "#p" + post.no;
}
return url;
} else {
throw new IllegalArgumentException();
}
}
@Override
public boolean boardFeature(BoardFeature boardFeature, Board board) {
switch (boardFeature) {
@ -191,6 +321,11 @@ public class Chan4 implements Site {
return endpoints;
}
@Override
public SiteRequestModifier requestModifier() {
return siteRequestModifier;
}
@Override
public void boards(final BoardsListener listener) {
requestQueue.add(new Chan4BoardsRequest(this, new Response.Listener<List<Board>>() {
@ -222,7 +357,7 @@ public class Chan4 implements Site {
@Override
public void post(Reply reply, final PostListener postListener) {
httpCallManager.makeHttpCall(new Chan4ReplyHttpCall(reply), new HttpCall.HttpCallback<Chan4ReplyHttpCall>() {
httpCallManager.makeHttpCall(new Chan4ReplyHttpCall(this, reply), new HttpCall.HttpCallback<Chan4ReplyHttpCall>() {
@Override
public void onHttpSuccess(Chan4ReplyHttpCall httpPost) {
postListener.onPostComplete(httpPost, httpPost.replyResponse);
@ -237,7 +372,7 @@ public class Chan4 implements Site {
@Override
public void delete(DeleteRequest deleteRequest, final DeleteListener deleteListener) {
httpCallManager.makeHttpCall(new Chan4DeleteHttpCall(deleteRequest), new HttpCall.HttpCallback<Chan4DeleteHttpCall>() {
httpCallManager.makeHttpCall(new Chan4DeleteHttpCall(this, deleteRequest), new HttpCall.HttpCallback<Chan4DeleteHttpCall>() {
@Override
public void onHttpSuccess(Chan4DeleteHttpCall httpPost) {
deleteListener.onDeleteComplete(httpPost, httpPost.deleteResponse);
@ -252,10 +387,17 @@ public class Chan4 implements Site {
@Override
public void login(LoginRequest loginRequest, final LoginListener loginListener) {
httpCallManager.makeHttpCall(new Chan4PassHttpCall(loginRequest), new HttpCall.HttpCallback<Chan4PassHttpCall>() {
passUser.set(loginRequest.user);
passPass.set(loginRequest.pass);
httpCallManager.makeHttpCall(new Chan4PassHttpCall(this, loginRequest), new HttpCall.HttpCallback<Chan4PassHttpCall>() {
@Override
public void onHttpSuccess(Chan4PassHttpCall httpCall) {
loginListener.onLoginComplete(httpCall, httpCall.loginResponse);
LoginResponse loginResponse = httpCall.loginResponse;
if (loginResponse.success) {
passToken.set(loginResponse.token);
}
loginListener.onLoginComplete(httpCall, loginResponse);
}
@Override
@ -264,4 +406,19 @@ public class Chan4 implements Site {
}
});
}
@Override
public void logout() {
passToken.set("");
}
@Override
public boolean isLoggedIn() {
return !passToken.get().isEmpty();
}
@Override
public LoginRequest getLoginDetails() {
return new LoginRequest(passUser.get(), passPass.get());
}
}

@ -43,7 +43,7 @@ public class Chan4BoardsRequest extends JsonReaderRequest<List<Board>> {
private final Site site;
public Chan4BoardsRequest(Site site, Listener<List<Board>> listener, ErrorListener errorListener) {
super(site.endpoints().boards(), listener, errorListener);
super(site.endpoints().boards().toString(), listener, errorListener);
this.site = site;
}

@ -17,6 +17,7 @@
*/
package org.floens.chan.core.site.sites.chan4;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.http.DeleteRequest;
import org.floens.chan.core.site.http.DeleteResponse;
import org.floens.chan.core.site.http.HttpCall;
@ -36,7 +37,8 @@ public class Chan4DeleteHttpCall extends HttpCall {
private final DeleteRequest deleteRequest;
public final DeleteResponse deleteResponse = new DeleteResponse();
public Chan4DeleteHttpCall(DeleteRequest deleteRequest) {
public Chan4DeleteHttpCall(Site site, DeleteRequest deleteRequest) {
super(site);
this.deleteRequest = deleteRequest;
}
@ -50,7 +52,7 @@ public class Chan4DeleteHttpCall extends HttpCall {
formBuilder.add("mode", "usrdel");
formBuilder.add("pwd", deleteRequest.savedReply.password);
requestBuilder.url(deleteRequest.site.endpoints().delete(deleteRequest.post));
requestBuilder.url(site.endpoints().delete(deleteRequest.post));
requestBuilder.post(formBuilder.build());
}

@ -17,6 +17,7 @@
*/
package org.floens.chan.core.site.sites.chan4;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.http.HttpCall;
import org.floens.chan.core.site.http.LoginRequest;
import org.floens.chan.core.site.http.LoginResponse;
@ -33,7 +34,8 @@ public class Chan4PassHttpCall extends HttpCall {
private final LoginRequest loginRequest;
public final LoginResponse loginResponse = new LoginResponse();
public Chan4PassHttpCall(LoginRequest loginRequest) {
public Chan4PassHttpCall(Site site, LoginRequest loginRequest) {
super(site);
this.loginRequest = loginRequest;
}
@ -46,7 +48,7 @@ public class Chan4PassHttpCall extends HttpCall {
formBuilder.add("id", loginRequest.user);
formBuilder.add("pin", loginRequest.pass);
requestBuilder.url(loginRequest.site.endpoints().login());
requestBuilder.url(site.endpoints().login());
requestBuilder.post(formBuilder.build());
}

@ -47,6 +47,8 @@ import java.util.concurrent.Future;
import javax.inject.Inject;
import okhttp3.HttpUrl;
import static org.floens.chan.Chan.getGraph;
/**
@ -84,7 +86,7 @@ public class Chan4ReaderRequest extends JsonReaderRequest<ChanLoaderResponse> {
private long startLoad;
public Chan4ReaderRequest(ChanLoaderRequestParams request) {
super(getChanUrl(request.loadable), request.listener, request.errorListener);
super(getChanUrl(request.loadable).toString(), request.listener, request.errorListener);
getGraph().inject(this);
// Copy the loadable and cached list. The cached array may changed/cleared by other threads.
@ -116,8 +118,8 @@ public class Chan4ReaderRequest extends JsonReaderRequest<ChanLoaderResponse> {
databaseSavedReplyManager = databaseManager.getDatabaseSavedReplyManager();
}
private static String getChanUrl(Loadable loadable) {
String url;
private static HttpUrl getChanUrl(Loadable loadable) {
HttpUrl url;
if (loadable.site == null) {
throw new NullPointerException("Loadable.site == null");
@ -497,7 +499,7 @@ public class Chan4ReaderRequest extends JsonReaderRequest<ChanLoaderResponse> {
}
if (countryCode != null && countryName != null) {
String countryUrl = endpoints.flag(builder, countryCode, Collections.<String, String>emptyMap());
HttpUrl countryUrl = endpoints.flag(builder, countryCode, Collections.<String, String>emptyMap());
builder.country(countryCode, countryName, countryUrl);
}

@ -46,7 +46,8 @@ public class Chan4ReplyHttpCall extends HttpCall {
public final Reply reply;
public final ReplyResponse replyResponse = new ReplyResponse();
public Chan4ReplyHttpCall(Reply reply) {
public Chan4ReplyHttpCall(Site site, Reply reply) {
super(site);
this.reply = reply;
}
@ -75,7 +76,7 @@ public class Chan4ReplyHttpCall extends HttpCall {
formBuilder.addFormDataPart("com", reply.comment);
if (!reply.noVerification) {
if (reply.captchaResponse != null) {
if (reply.captchaChallenge != null) {
formBuilder.addFormDataPart("recaptcha_challenge_field", reply.captchaChallenge);
formBuilder.addFormDataPart("recaptcha_response_field", reply.captchaResponse);
@ -94,13 +95,8 @@ public class Chan4ReplyHttpCall extends HttpCall {
formBuilder.addFormDataPart("spoiler", "on");
}
Site site = reply.loadable.getSite();
requestBuilder.url(site.endpoints().reply(reply.loadable));
requestBuilder.post(formBuilder.build());
if (reply.noVerification) {
requestBuilder.addHeader("Cookie", "pass_id=" + reply.passId);
}
}
@Override

@ -208,7 +208,7 @@ public class TestActivity extends Activity implements View.OnClickListener {
public void onChanLoaderData(ChanThread result) {
for (Post post : result.posts) {
if (post.image != null) {
final String imageUrl = post.image.imageUrl;
final String imageUrl = post.image.imageUrl.toString();
fileCache.downloadFile(imageUrl, new FileCache.DownloadedCallback() {
@Override
public void onProgress(long downloaded, long total, boolean done) {

@ -37,14 +37,14 @@ public class PostsFilter {
public static final Comparator<Post> IMAGE_COMPARATOR = new Comparator<Post>() {
@Override
public int compare(Post lhs, Post rhs) {
return rhs.images - lhs.images;
return rhs.getImages() - lhs.getImages();
}
};
public static final Comparator<Post> REPLY_COMPARATOR = new Comparator<Post>() {
@Override
public int compare(Post lhs, Post rhs) {
return rhs.replies - lhs.replies;
return rhs.getReplies() - lhs.getReplies();
}
};

@ -217,7 +217,7 @@ public class CardPostCell extends CardView implements PostCellInterface, View.On
comment.setText(commentText);
comment.setTextColor(theme.textPrimary);
replies.setText(getResources().getString(R.string.card_stats, post.replies, post.images));
replies.setText(getResources().getString(R.string.card_stats, post.getReplies(), post.getImages()));
}
private void unbindPost(Post post) {

@ -51,7 +51,6 @@ import android.widget.TextView;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import org.floens.chan.Chan;
import org.floens.chan.R;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.PostImage;
@ -395,10 +394,10 @@ public class PostCell extends LinearLayout implements PostCellInterface {
title.setText(TextUtils.concat(titleParts.toArray(new CharSequence[titleParts.size()])));
icons.edit();
icons.set(PostIcons.STICKY, post.sticky);
icons.set(PostIcons.CLOSED, post.closed);
icons.set(PostIcons.STICKY, post.isSticky());
icons.set(PostIcons.CLOSED, post.isClosed());
icons.set(PostIcons.DELETED, post.deleted.get());
icons.set(PostIcons.ARCHIVED, post.archived);
icons.set(PostIcons.ARCHIVED, post.isArchived());
if (!isEmpty(post.country)) {
icons.set(PostIcons.COUNTRY, true);
@ -445,14 +444,14 @@ public class PostCell extends LinearLayout implements PostCellInterface {
repliesFromSize = post.repliesFrom.size();
}
if ((!threadMode && post.replies > 0) || (repliesFromSize > 0)) {
if ((!threadMode && post.getReplies() > 0) || (repliesFromSize > 0)) {
replies.setVisibility(View.VISIBLE);
int replyCount = threadMode ? repliesFromSize : post.replies;
int replyCount = threadMode ? repliesFromSize : post.getReplies();
String text = getResources().getQuantityString(R.plurals.reply, replyCount, replyCount);
if (!threadMode && post.images > 0) {
text += ", " + getResources().getQuantityString(R.plurals.image, post.images, post.images);
if (!threadMode && post.getImages() > 0) {
text += ", " + getResources().getQuantityString(R.plurals.image, post.getImages(), post.getImages());
}
replies.setText(text);
@ -674,7 +673,7 @@ public class PostCell extends LinearLayout implements PostCellInterface {
countryTextColor = theme.detailsColor;
countryTextSize = textSize;
countryIconRequest = getGraph().getImageLoader().get(post.countryUrl, new ImageLoader.ImageListener() {
countryIconRequest = getGraph().getImageLoader().get(post.countryUrl.toString(), new ImageLoader.ImageListener() {
@Override
public void onResponse(ImageLoader.ImageContainer response, boolean isImmediate) {
if (response.getBitmap() != null) {

@ -29,7 +29,6 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.floens.chan.Chan;
import org.floens.chan.R;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.ChanThread;
@ -124,16 +123,16 @@ public class ThreadStatusCell extends LinearLayout implements View.OnClickListen
Board board = op.board;
if (board != null) {
SpannableString replies = new SpannableString(op.replies + "R");
if (op.replies >= board.bumpLimit) {
SpannableString replies = new SpannableString(op.getReplies() + "R");
if (op.getReplies() >= board.bumpLimit) {
replies.setSpan(new StyleSpan(Typeface.ITALIC), 0, replies.length(), 0);
}
SpannableString images = new SpannableString(op.images + "I");
if (op.images >= board.imageLimit) {
SpannableString images = new SpannableString(op.getImages() + "I");
if (op.getImages() >= board.imageLimit) {
images.setSpan(new StyleSpan(Typeface.ITALIC), 0, images.length(), 0);
}
text.setText(TextUtils.concat(statusText, replies, " / ", images, " / ", String.valueOf(op.uniqueIps) + "P"));
text.setText(TextUtils.concat(statusText, replies, " / ", images, " / ", String.valueOf(op.getUniqueIps()) + "P"));
}
return update;

@ -198,7 +198,7 @@ public class ImageViewerController extends Controller implements ImageViewerPres
saveShare(true, postImage);
break;
case OPEN_BROWSER_ID:
AndroidUtils.openLinkInBrowser((Activity) context, postImage.imageUrl);
AndroidUtils.openLinkInBrowser((Activity) context, postImage.imageUrl.toString());
break;
case SEARCH_ID:
List<FloatingMenuItem> items = new ArrayList<>();
@ -211,7 +211,7 @@ public class ImageViewerController extends Controller implements ImageViewerPres
public void onFloatingMenuItemClicked(FloatingMenu menu, FloatingMenuItem item) {
for (ImageSearch imageSearch : ImageSearch.engines) {
if (((Integer) item.getId()) == imageSearch.getId()) {
AndroidUtils.openLinkInBrowser((Activity) context, imageSearch.getUrl(presenter.getCurrentPostImage().imageUrl));
AndroidUtils.openLinkInBrowser((Activity) context, imageSearch.getUrl(presenter.getCurrentPostImage().imageUrl.toString()));
break;
}
}
@ -234,7 +234,7 @@ public class ImageViewerController extends Controller implements ImageViewerPres
private void saveShare(boolean share, PostImage postImage) {
if (share && ChanSettings.shareUrl.get()) {
AndroidUtils.shareLink(postImage.imageUrl);
AndroidUtils.shareLink(postImage.imageUrl.toString());
} else {
ImageSaveTask task = new ImageSaveTask(postImage);
task.setShare(share);
@ -373,7 +373,7 @@ public class ImageViewerController extends Controller implements ImageViewerPres
}
});
imageLoader.get(postImage.thumbnailUrl, new ImageLoader.ImageListener() {
imageLoader.get(postImage.thumbnailUrl.toString(), new ImageLoader.ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "onErrorResponse for preview in transition in ImageViewerController, cannot show correct transition bitmap");
@ -395,7 +395,7 @@ public class ImageViewerController extends Controller implements ImageViewerPres
return;
}
imageLoader.get(postImage.thumbnailUrl, new ImageLoader.ImageListener() {
imageLoader.get(postImage.thumbnailUrl.toString(), new ImageLoader.ImageListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "onErrorResponse for preview out transition in ImageViewerController, cannot show correct transition bitmap");

@ -28,12 +28,12 @@ import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.Toast;
import org.floens.chan.Chan;
import org.floens.chan.R;
import org.floens.chan.core.database.DatabaseManager;
import org.floens.chan.core.manager.BoardManager;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.core.site.Sites;
import org.floens.chan.ui.activity.StartActivity;
import org.floens.chan.ui.helper.HintPopup;
import org.floens.chan.ui.helper.RefreshUIMessage;
@ -115,7 +115,8 @@ public class MainSettingsController extends SettingsController implements Toolba
populatePreferences();
onWatchEnabledChanged(ChanSettings.watchEnabled.get());
onPassEnabledChanged(ChanSettings.passLoggedIn());
// TODO(multi-site)
onPassEnabledChanged(Sites.defaultSite().isLoggedIn());
buildPreferences();

@ -29,7 +29,6 @@ import android.widget.TextView;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.manager.ReplyManager;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.Sites;
import org.floens.chan.core.site.http.HttpCall;
@ -61,6 +60,8 @@ public class PassSettingsController extends Controller implements View.OnClickLi
private EditText inputPin;
private TextView authenticated;
private Site site;
public PassSettingsController(Context context) {
super(context);
}
@ -70,6 +71,9 @@ public class PassSettingsController extends Controller implements View.OnClickLi
super.onCreate();
getGraph().inject(this);
// TODO(multi-site) some selector of some sorts
site = Sites.defaultSite();
navigationItem.setTitle(R.string.settings_screen_pass);
view = inflateRes(R.layout.controller_pass);
@ -91,8 +95,9 @@ public class PassSettingsController extends Controller implements View.OnClickLi
bottomDescription.setText(Html.fromHtml(getString(R.string.setting_pass_bottom_description)));
bottomDescription.setMovementMethod(LinkMovementMethod.getInstance());
inputToken.setText(ChanSettings.passToken.get());
inputPin.setText(ChanSettings.passPin.get());
LoginRequest loginDetails = site.getLoginDetails();
inputToken.setText(loginDetails.user);
inputPin.setText(loginDetails.pass);
// Sanity check
if (parentController.view.getWindowToken() == null) {
@ -115,7 +120,7 @@ public class PassSettingsController extends Controller implements View.OnClickLi
public void onClick(View v) {
if (v == button) {
if (loggedIn()) {
ChanSettings.passId.set("");
deauth();
crossfadeView.toggle(true, true);
button.setText(R.string.setting_pass_login);
hideError();
@ -146,7 +151,6 @@ public class PassSettingsController extends Controller implements View.OnClickLi
private void authSuccess(LoginResponse response) {
crossfadeView.toggle(false, true);
button.setText(R.string.setting_pass_logout);
ChanSettings.passId.set(response.token);
authenticated.setText(response.message);
((PassSettingControllerListener) previousSiblingController).onPassEnabledChanged(true);
}
@ -175,12 +179,14 @@ public class PassSettingsController extends Controller implements View.OnClickLi
button.setText(R.string.setting_pass_logging_in);
hideError();
ChanSettings.passToken.set(inputToken.getText().toString());
ChanSettings.passPin.set(inputPin.getText().toString());
// TODO(multi-site)
String user = inputToken.getText().toString();
String pass = inputPin.getText().toString();
site.login(new LoginRequest(user, pass), this);
}
// TODO(multi-site) some selector of some sorts
Site site = Sites.defaultSite();
site.login(new LoginRequest(site, ChanSettings.passToken.get(), ChanSettings.passPin.get()), this);
private void deauth() {
site.logout();
}
private void showError(String error) {
@ -194,7 +200,7 @@ public class PassSettingsController extends Controller implements View.OnClickLi
}
private boolean loggedIn() {
return ChanSettings.passId.get().length() > 0;
return site.isLoggedIn();
}
public interface PassSettingControllerListener {

@ -19,17 +19,13 @@ package org.floens.chan.ui.controller;
import android.annotation.SuppressLint;
import android.content.Context;
import android.webkit.CookieManager;
import android.webkit.WebSettings;
import android.webkit.WebView;
import org.floens.chan.R;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.Sites;
import org.floens.chan.ui.helper.PostHelper;
import okhttp3.HttpUrl;
@ -42,7 +38,6 @@ public class ReportController extends Controller {
this.post = post;
}
@SuppressWarnings("deprecation")
@SuppressLint("SetJavaScriptEnabled")
@Override
public void onCreate() {
@ -50,25 +45,16 @@ public class ReportController extends Controller {
navigationItem.title = context.getString(R.string.report_screen, PostHelper.getTitle(post, null));
Site site = post.board.getSite();
String url = site.endpoints().report(post);
if (site == Sites.CHAN4) {
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
if (ChanSettings.passLoggedIn()) {
HttpUrl parsed = HttpUrl.parse(url);
String domain = parsed.scheme() + "://" + parsed.host() + "/";
for (String cookie : ChanUrls.getReportCookies(ChanSettings.passId.get())) {
cookieManager.setCookie(domain, cookie);
}
}
}
HttpUrl url = site.endpoints().report(post);
WebView webView = new WebView(context);
site.requestModifier().modifyWebView(webView);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
webView.loadUrl(url);
webView.loadUrl(url.toString());
view = webView;
}
}

@ -190,10 +190,10 @@ public class WatchNotifier extends Service {
List<CharSequence> expandedLines = new ArrayList<>();
for (Post postForExpandedLine : postsForExpandedLines) {
CharSequence prefix;
if (postForExpandedLine.title.length() <= SUBJECT_LENGTH) {
prefix = postForExpandedLine.title;
if (postForExpandedLine.getTitle().length() <= SUBJECT_LENGTH) {
prefix = postForExpandedLine.getTitle();
} else {
prefix = postForExpandedLine.title.subSequence(0, SUBJECT_LENGTH);
prefix = postForExpandedLine.getTitle().subSequence(0, SUBJECT_LENGTH);
}
String comment = postForExpandedLine.image != null ? IMAGE_TEXT : "";

@ -129,16 +129,16 @@ public class MultiImageView extends FrameLayout implements View.OnClickListener
public boolean onMeasured(View view) {
switch (newMode) {
case LOWRES:
setThumbnail(postImage.thumbnailUrl);
setThumbnail(postImage.thumbnailUrl.toString());
break;
case BIGIMAGE:
setBigImage(postImage.imageUrl);
setBigImage(postImage.imageUrl.toString());
break;
case GIF:
setGif(postImage.imageUrl);
setGif(postImage.imageUrl.toString());
break;
case MOVIE:
setVideo(postImage.imageUrl);
setVideo(postImage.imageUrl.toString());
break;
}
return true;

@ -52,7 +52,7 @@ public class PostImageThumbnailView extends ThumbnailView {
this.postImage = postImage;
if (postImage != null) {
setUrl(postImage.thumbnailUrl, width, height);
setUrl(postImage.thumbnailUrl.toString(), width, height);
} else {
setUrl(null, width, height);
}

@ -93,6 +93,10 @@ public class AndroidUtils {
return PreferenceManager.getDefaultSharedPreferences(Chan.getInstance());
}
public static SharedPreferences getPreferences(String name) {
return Chan.getInstance().getSharedPreferences(name, Context.MODE_PRIVATE);
}
/**
* Tries to open an app that can open the specified URL.<br>
* If this app will open the link then show a chooser to the user without this app.<br>

Loading…
Cancel
Save