Make http calls abstract, call through Site

multisite
Floens 9 years ago
parent aa4f96cacf
commit f8c182bba5
  1. 12
      Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java
  2. 13
      Clover/app/src/main/java/org/floens/chan/core/di/ChanGraph.java
  3. 43
      Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java
  4. 28
      Clover/app/src/main/java/org/floens/chan/core/model/BoardReference.java
  5. 7
      Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java
  6. 44
      Clover/app/src/main/java/org/floens/chan/core/presenter/ReplyPresenter.java
  7. 27
      Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java
  8. 70
      Clover/app/src/main/java/org/floens/chan/core/site/Site.java
  9. 25
      Clover/app/src/main/java/org/floens/chan/core/site/SiteEndpoints.java
  10. 37
      Clover/app/src/main/java/org/floens/chan/core/site/http/DeleteRequest.java
  11. 24
      Clover/app/src/main/java/org/floens/chan/core/site/http/DeleteResponse.java
  12. 66
      Clover/app/src/main/java/org/floens/chan/core/site/http/HttpCall.java
  13. 63
      Clover/app/src/main/java/org/floens/chan/core/site/http/HttpCallManager.java
  14. 33
      Clover/app/src/main/java/org/floens/chan/core/site/http/LoginRequest.java
  15. 27
      Clover/app/src/main/java/org/floens/chan/core/site/http/LoginResponse.java
  16. 16
      Clover/app/src/main/java/org/floens/chan/core/site/http/Reply.java
  17. 42
      Clover/app/src/main/java/org/floens/chan/core/site/http/ReplyResponse.java
  18. 102
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java
  19. 33
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4DeleteHttpCall.java
  20. 37
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4PassHttpCall.java
  21. 2
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReaderRequest.java
  22. 55
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4ReplyHttpCall.java
  23. 2
      Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/PostParseCallable.java
  24. 46
      Clover/app/src/main/java/org/floens/chan/ui/controller/PassSettingsController.java
  25. 29
      Clover/app/src/main/java/org/floens/chan/ui/controller/ReportController.java
  26. 4
      Clover/app/src/main/java/org/floens/chan/ui/helper/ImagePickDelegate.java
  27. 2
      Clover/app/src/main/java/org/floens/chan/ui/layout/ReplyLayout.java

@ -24,14 +24,6 @@ public class ChanUrls {
return "6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc";
}
public static String getReplyUrl(String board) {
return "https://sys.4chan.org/" + board + "/post";
}
public static String getDeleteUrl(String board) {
return "https://sys.4chan.org/" + board + "/imgboard.php";
}
public static String getBoardUrlDesktop(String board) {
return scheme() + "://boards.4chan.org/" + board + "/";
}
@ -52,10 +44,6 @@ public class ChanUrls {
return "https://sys.4chan.org/auth";
}
public static String getReportDomain() {
return "https://sys.4chan.org/";
}
public static String[] getReportCookies(String passId) {
return new String[]{"pass_enabled=1;", "pass_id=" + passId + ";"};
}

@ -8,16 +8,18 @@ import org.floens.chan.chan.ChanLoader;
import org.floens.chan.chan.ChanParser;
import org.floens.chan.core.cache.FileCache;
import org.floens.chan.core.database.DatabaseManager;
import org.floens.chan.core.http.ReplyManager;
import org.floens.chan.core.manager.ReplyManager;
import org.floens.chan.core.manager.BoardManager;
import org.floens.chan.core.manager.FilterEngine;
import org.floens.chan.core.manager.WatchManager;
import org.floens.chan.core.site.loaders.Chan4ReaderRequest;
import org.floens.chan.core.site.http.HttpCallManager;
import org.floens.chan.core.site.sites.chan4.Chan4ReaderRequest;
import org.floens.chan.core.presenter.ImageViewerPresenter;
import org.floens.chan.core.presenter.ReplyPresenter;
import org.floens.chan.core.presenter.ThreadPresenter;
import org.floens.chan.core.receiver.WatchUpdateReceiver;
import org.floens.chan.core.saver.ImageSaveTask;
import org.floens.chan.core.site.sites.chan4.Chan4;
import org.floens.chan.ui.activity.StartActivity;
import org.floens.chan.ui.adapter.DrawerAdapter;
import org.floens.chan.ui.adapter.PostsFilter;
@ -46,6 +48,9 @@ import dagger.Component;
NetModule.class
})
@Singleton
/**
* Note: please avoid adding inject() statements for Sites.
*/
public interface ChanGraph {
ChanParser getChanParser();
@ -61,6 +66,8 @@ public interface ChanGraph {
FileCache getFileCache();
HttpCallManager getHttpCallManager();
void inject(Chan chan);
void inject(MainSettingsController mainSettingsController);
@ -116,4 +123,6 @@ public interface ChanGraph {
void inject(ViewThreadController viewThreadController);
void inject(WatchManager.PinWatcher pinWatcher);
void inject(Chan4 chan4);
}

@ -15,48 +15,32 @@
* 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.http;
package org.floens.chan.core.manager;
import android.content.Context;
import org.floens.chan.core.di.UserAgentProvider;
import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Reply;
import org.floens.chan.core.site.http.Reply;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Singleton;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* To send an reply to 4chan.
* Manages replies.
*/
@Singleton
public class ReplyManager {
private static final int TIMEOUT = 30000;
private final Context context;
private String userAgent;
private OkHttpClient client;
private Map<Loadable, Reply> drafts = new HashMap<>();
@Inject
public ReplyManager(Context context, UserAgentProvider userAgentProvider) {
public ReplyManager(Context context) {
this.context = context;
userAgent = userAgentProvider.getUserAgent();
client = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.build();
}
public Reply getReply(Loadable loadable) {
@ -85,23 +69,4 @@ public class ReplyManager {
public File getPickFile() {
return new File(context.getCacheDir(), "picked_file");
}
public void makeHttpCall(HttpCall httpCall, HttpCallback<? extends HttpCall> callback) {
httpCall.setCallback(callback);
Request.Builder requestBuilder = new Request.Builder();
httpCall.setup(requestBuilder);
requestBuilder.header("User-Agent", userAgent);
Request request = requestBuilder.build();
client.newCall(request).enqueue(httpCall);
}
public interface HttpCallback<T extends HttpCall> {
void onHttpSuccess(T httpPost);
void onHttpFail(T httpPost);
}
}

@ -0,0 +1,28 @@
/*
* 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.model;
public interface BoardReference {
/**
* Get the Board object that this model references.
*
* @return a {@link Board}
*/
Board getBoard();
}

@ -35,7 +35,7 @@ import org.floens.chan.core.site.Site;
* references the same loadable and that the loadable is properly saved in the database.
*/
@DatabaseTable
public class Loadable implements SiteReference {
public class Loadable implements SiteReference, BoardReference {
@DatabaseField(generatedId = true)
public int id;
@ -123,6 +123,11 @@ public class Loadable implements SiteReference {
return site;
}
@Override
public Board getBoard() {
return board;
}
public void setTitle(String title) {
if (!TextUtils.equals(this.title, title)) {
this.title = title;

@ -22,17 +22,20 @@ import android.text.TextUtils;
import org.floens.chan.R;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.core.database.DatabaseManager;
import org.floens.chan.core.http.ReplyHttpCall;
import org.floens.chan.core.http.ReplyManager;
import org.floens.chan.core.manager.ReplyManager;
import org.floens.chan.core.manager.BoardManager;
import org.floens.chan.core.manager.WatchManager;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.ChanThread;
import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.Reply;
import org.floens.chan.core.model.SavedReply;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.http.HttpCall;
import org.floens.chan.core.site.http.HttpCallManager;
import org.floens.chan.core.site.http.ReplyResponse;
import org.floens.chan.core.site.http.Reply;
import org.floens.chan.ui.helper.ImagePickDelegate;
import org.floens.chan.ui.layout.CaptchaCallback;
import org.floens.chan.ui.layout.CaptchaLayoutInterface;
@ -49,7 +52,7 @@ import static org.floens.chan.utils.AndroidUtils.getReadableFileSize;
import static org.floens.chan.utils.AndroidUtils.getRes;
import static org.floens.chan.utils.AndroidUtils.getString;
public class ReplyPresenter implements ReplyManager.HttpCallback<ReplyHttpCall>, CaptchaCallback, ImagePickDelegate.ImagePickCallback {
public class ReplyPresenter implements CaptchaCallback, ImagePickDelegate.ImagePickCallback, Site.PostListener {
public enum Page {
INPUT,
CAPTCHA,
@ -70,6 +73,9 @@ public class ReplyPresenter implements ReplyManager.HttpCallback<ReplyHttpCall>,
@Inject
WatchManager watchManager;
@Inject
HttpCallManager httpCallManager;
@Inject
DatabaseManager databaseManager;
@ -189,21 +195,20 @@ public class ReplyPresenter implements ReplyManager.HttpCallback<ReplyHttpCall>,
public void onSubmitClicked() {
callback.loadViewsIntoDraft(draft);
draft.board = loadable.boardCode;
draft.resto = loadable.isThreadMode() ? loadable.no : -1;
draft.loadable = loadable;
if (ChanSettings.passLoggedIn()) {
draft.usePass = true;
draft.noVerification = true;
draft.passId = ChanSettings.passId.get();
} else {
draft.usePass = false;
draft.noVerification = false;
draft.passId = null;
}
draft.spoilerImage = draft.spoilerImage && board.spoilers;
draft.captchaResponse = null;
if (draft.usePass) {
if (draft.noVerification) {
makeSubmitCall();
} else {
switchPage(Page.CAPTCHA, true);
@ -211,8 +216,8 @@ public class ReplyPresenter implements ReplyManager.HttpCallback<ReplyHttpCall>,
}
@Override
public void onHttpSuccess(ReplyHttpCall replyCall) {
if (replyCall.posted) {
public void onPostComplete(HttpCall httpCall, ReplyResponse replyResponse) {
if (replyResponse.posted) {
if (ChanSettings.postPinThread.get() && loadable.isThreadMode()) {
ChanThread thread = callback.getThread();
if (thread != null) {
@ -220,7 +225,7 @@ public class ReplyPresenter implements ReplyManager.HttpCallback<ReplyHttpCall>,
}
}
SavedReply savedReply = new SavedReply(loadable.boardCode, replyCall.postNo, replyCall.password);
SavedReply savedReply = new SavedReply(loadable.boardCode, replyResponse.postNo, replyResponse.password);
databaseManager.runTask(databaseManager.getDatabaseSavedReplyManager().saveReply(savedReply));
switchPage(Page.INPUT, false);
@ -234,23 +239,20 @@ public class ReplyPresenter implements ReplyManager.HttpCallback<ReplyHttpCall>,
callback.onPosted();
if (bound && !loadable.isThreadMode()) {
callback.showThread(databaseManager.getDatabaseLoadableManager().get(Loadable.forThread(loadable.site, loadable.board, replyCall.postNo)));
callback.showThread(databaseManager.getDatabaseLoadableManager().get(Loadable.forThread(loadable.site, loadable.board, replyResponse.postNo)));
}
} else {
if (replyCall.errorMessage == null) {
replyCall.errorMessage = getString(R.string.reply_error);
if (replyResponse.errorMessage == null) {
replyResponse.errorMessage = getString(R.string.reply_error);
}
switchPage(Page.INPUT, true);
callback.openMessage(true, false, replyCall.errorMessage, true);
if (replyCall.probablyBanned) {
// callback.openMessageWebview();
}
callback.openMessage(true, false, replyResponse.errorMessage, true);
}
}
@Override
public void onHttpFail(ReplyHttpCall httpPost) {
public void onPostError(HttpCall httpCall) {
switchPage(Page.INPUT, true);
callback.openMessage(true, false, getString(R.string.reply_error), true);
}
@ -338,7 +340,7 @@ public class ReplyPresenter implements ReplyManager.HttpCallback<ReplyHttpCall>,
}
private void makeSubmitCall() {
replyManager.makeHttpCall(new ReplyHttpCall(draft), this);
loadable.getSite().post(draft, this);
switchPage(Page.LOADING, true);
}

@ -25,8 +25,7 @@ import org.floens.chan.chan.ChanLoader;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.core.database.DatabaseManager;
import org.floens.chan.core.exception.ChanLoaderException;
import org.floens.chan.core.http.DeleteHttpCall;
import org.floens.chan.core.http.ReplyManager;
import org.floens.chan.core.manager.ReplyManager;
import org.floens.chan.core.manager.WatchManager;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.ChanThread;
@ -40,6 +39,10 @@ import org.floens.chan.core.model.SavedReply;
import org.floens.chan.core.pool.ChanLoaderFactory;
import org.floens.chan.core.settings.ChanSettings;
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;
import org.floens.chan.core.site.http.HttpCallManager;
import org.floens.chan.ui.adapter.PostAdapter;
import org.floens.chan.ui.adapter.PostsFilter;
import org.floens.chan.ui.cell.PostCellInterface;
@ -85,6 +88,9 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
@Inject
ReplyManager replyManager;
@Inject
HttpCallManager httpCallManager;
@Inject
ChanLoaderFactory chanLoaderFactory;
@ -426,7 +432,10 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
menu.add(new FloatingMenuItem(POST_OPTION_OPEN_BROWSER, R.string.action_open_browser));
menu.add(new FloatingMenuItem(POST_OPTION_SHARE, R.string.post_share));
menu.add(new FloatingMenuItem(POST_OPTION_COPY_TEXT, R.string.post_copy_text));
menu.add(new FloatingMenuItem(POST_OPTION_REPORT, R.string.post_report));
if (loadable.getSite().feature(Site.Feature.POST_REPORT)) {
menu.add(new FloatingMenuItem(POST_OPTION_REPORT, R.string.post_report));
}
if (!loadable.isThreadMode()) {
menu.add(new FloatingMenuItem(POST_OPTION_HIDE, R.string.post_hide));
@ -603,14 +612,14 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
databaseManager.getDatabaseSavedReplyManager().findSavedReply(post.boardId, post.no)
);
if (reply != null) {
replyManager.makeHttpCall(new DeleteHttpCall(reply, onlyImageDelete), new ReplyManager.HttpCallback<DeleteHttpCall>() {
loadable.getSite().delete(new DeleteRequest(loadable.getSite(), post, reply, onlyImageDelete), new Site.DeleteListener() {
@Override
public void onHttpSuccess(DeleteHttpCall httpPost) {
public void onDeleteComplete(HttpCall httpPost, DeleteResponse deleteResponse) {
String message;
if (httpPost.deleted) {
if (deleteResponse.deleted) {
message = getString(R.string.delete_success);
} else if (!TextUtils.isEmpty(httpPost.errorMessage)) {
message = httpPost.errorMessage;
} else if (!TextUtils.isEmpty(deleteResponse.errorMessage)) {
message = deleteResponse.errorMessage;
} else {
message = getString(R.string.delete_error);
}
@ -618,7 +627,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt
}
@Override
public void onHttpFail(DeleteHttpCall httpPost) {
public void onDeleteError(HttpCall httpCall) {
threadPresenterCallback.hideDeleting(getString(R.string.delete_error));
}
});

@ -1,23 +1,65 @@
/*
* 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 org.floens.chan.chan.ChanLoaderRequest;
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.site.http.DeleteRequest;
import org.floens.chan.core.site.http.DeleteResponse;
import org.floens.chan.core.site.http.HttpCall;
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.core.site.http.ReplyResponse;
public interface Site {
enum Feature {
/**
* This site supports posting. (Or rather, we've implemented support for it.)
*
* @see #post(Reply, PostListener)
* @see SiteEndpoints#reply(Loadable)
*/
POSTING,
/**
* This site supports deleting posts.
*
* @see #delete(DeleteRequest, DeleteListener)
* @see SiteEndpoints#delete(Post)
*/
POST_DELETE,
/**
* This site supports reporting posts.
*
* @see SiteEndpoints#report(Post)
*/
POST_REPORT,
/**
* This site supports some sort of login (like 4pass).
*
* @see #login(LoginRequest, LoginListener)
* @see SiteEndpoints#login()
*/
LOGIN
}
@ -75,11 +117,35 @@ public interface Site {
void boards(BoardsListener boardsListener);
interface BoardsListener {
void onBoardsReceived(Boards boards);
}
Board board(String name);
ChanLoaderRequest loaderRequest(ChanLoaderRequestParams request);
interface BoardsListener {
void onBoardsReceived(Boards boards);
void post(Reply reply, PostListener postListener);
interface PostListener {
void onPostComplete(HttpCall httpCall, ReplyResponse replyResponse);
void onPostError(HttpCall httpCall);
}
void delete(DeleteRequest deleteRequest, DeleteListener deleteListener);
interface DeleteListener {
void onDeleteComplete(HttpCall httpCall, DeleteResponse deleteResponse);
void onDeleteError(HttpCall httpCall);
}
void login(LoginRequest loginRequest, LoginListener loginListener);
interface LoginListener {
void onLoginComplete(HttpCall httpCall, LoginResponse loginResponse);
void onLoginError(HttpCall httpCall);
}
}

@ -1,3 +1,20 @@
/*
* 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 org.floens.chan.core.model.Board;
@ -22,5 +39,11 @@ public interface SiteEndpoints {
String boards();
String reply(Board board, Loadable thread);
String reply(Loadable thread);
String delete(Post post);
String report(Post post);
String login();
}

@ -0,0 +1,37 @@
/*
* 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.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;
this.post = post;
this.savedReply = savedReply;
this.imageOnly = imageOnly;
}
}

@ -0,0 +1,24 @@
/*
* 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.http;
public class DeleteResponse {
public boolean deleted;
public String errorMessage;
}

@ -15,7 +15,7 @@
* 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.http;
package org.floens.chan.core.site.http;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.IOUtils;
@ -28,29 +28,24 @@ import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
/**
* Http calls are an abstraction over a normal OkHttp call.
* <p>These HttpCalls are used for emulating &lt;form&gt; elements used for posting, reporting, deleting, etc.
* <p>Implement {@link #setup(Request.Builder)} and {@link #process(Response, String)}.
* {@code setup()} is called on the main thread, set up up the request builder here. {@code execute()} is
* called on a worker thread after the response was executed, do something with the response here.
*/
public abstract class HttpCall implements Callback {
private static final String TAG = "HttpCall";
private boolean successful = false;
private ReplyManager.HttpCallback callback;
public void setSuccessful(boolean successful) {
this.successful = successful;
}
private HttpCallback callback;
private Exception exception;
public abstract void setup(Request.Builder requestBuilder);
public abstract void process(Response response, String result) throws IOException;
@SuppressWarnings("unchecked")
public void postUI(boolean successful) {
if (successful) {
callback.onHttpSuccess(this);
} else {
callback.onHttpFail(this);
}
}
@Override
public void onResponse(Call call, Response response) {
try {
@ -61,31 +56,60 @@ public abstract class HttpCall implements Callback {
} else {
onFailure(call, null);
}
} catch (IOException e) {
} catch (Exception e) {
exception = e;
Logger.e(TAG, "IOException processing response", e);
} finally {
IOUtils.closeQuietly(response.body());
}
if (successful) {
callSuccess();
} else {
callFail(exception);
}
}
@Override
public void onFailure(Call call, IOException e) {
callFail(e);
}
public Exception getException() {
return exception;
}
public boolean isSuccessful() {
return successful;
}
private void callSuccess() {
AndroidUtils.runOnUiThread(new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
postUI(successful);
callback.onHttpSuccess(HttpCall.this);
}
});
}
@Override
public void onFailure(Call call, IOException e) {
private void callFail(final Exception e) {
AndroidUtils.runOnUiThread(new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
postUI(false);
callback.onHttpFail(HttpCall.this, e);
}
});
}
void setCallback(ReplyManager.HttpCallback<? extends HttpCall> callback) {
public void setCallback(HttpCallback<? extends HttpCall> callback) {
this.callback = callback;
}
public interface HttpCallback<T extends HttpCall> {
void onHttpSuccess(T httpCall);
void onHttpFail(T httpCall, Exception e);
}
}

@ -0,0 +1,63 @@
/*
* 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.http;
import org.floens.chan.core.di.UserAgentProvider;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Singleton;
import okhttp3.OkHttpClient;
import okhttp3.Request;
/**
* Manages the {@link HttpCall} executions.
*/
@Singleton
public class HttpCallManager {
private static final int TIMEOUT = 30000;
private UserAgentProvider userAgentProvider;
private OkHttpClient client;
@Inject
public HttpCallManager(UserAgentProvider userAgentProvider) {
this.userAgentProvider = userAgentProvider;
client = new OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.build();
}
public void makeHttpCall(HttpCall httpCall, HttpCall.HttpCallback<? extends HttpCall> callback) {
httpCall.setCallback(callback);
Request.Builder requestBuilder = new Request.Builder();
httpCall.setup(requestBuilder);
requestBuilder.header("User-Agent", userAgentProvider.getUserAgent());
Request request = requestBuilder.build();
client.newCall(request).enqueue(httpCall);
}
}

@ -0,0 +1,33 @@
/*
* 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.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;
this.user = user;
this.pass = pass;
}
}

@ -0,0 +1,27 @@
/*
* 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.http;
public class LoginResponse {
public boolean success;
public String message;
// TODO(multi-site) make this a cookie abstraction
public String token;
}

@ -15,7 +15,9 @@
* 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.model;
package org.floens.chan.core.site.http;
import org.floens.chan.core.model.Loadable;
import java.io.File;
@ -24,17 +26,19 @@ import java.io.File;
*/
public class Reply {
/**
* Optional. Null when ReCaptcha v2 was used or a 4pass
* Optional. {@code null} when ReCaptcha v2 was used or a 4pass
*/
public String captchaChallenge;
/**
* Optional. Null when a 4pass was used.
* Optional. {@code null} when a 4pass was used.
*/
public String captchaResponse;
public boolean usePass = false;
public String board;
public int resto;
// TODO(multi-site) flip boolean
public boolean noVerification = false;
public Loadable loadable;
public String passId;
public File file;

@ -0,0 +1,42 @@
/*
* 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.http;
import org.floens.chan.core.site.Site;
/**
* Generic response for {@link Site#post(Reply, Site.PostListener)} that the reply layout uses.
*/
public class ReplyResponse {
/**
* {@code true} if the post when through, {@code false} otherwise.
*/
public boolean posted;
/**
* Error message used to show to the user if {@link #posted} is {@code false}.
* <p>Optional
*/
public String errorMessage;
// TODO(multi-site)
public int threadNo;
public int postNo;
public String password;
public boolean probablyBanned;
}

@ -1,5 +1,23 @@
/*
* 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.sites.chan4;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
@ -11,7 +29,11 @@ import org.floens.chan.core.model.Post;
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.loaders.Chan4ReaderRequest;
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.Reply;
import org.floens.chan.utils.Logger;
import java.util.ArrayList;
@ -21,6 +43,8 @@ import java.util.Locale;
import java.util.Map;
import java.util.Random;
import javax.inject.Inject;
import static org.floens.chan.Chan.getGraph;
public class Chan4 implements Site {
@ -28,6 +52,12 @@ public class Chan4 implements Site {
private static final Random random = new Random();
@Inject
HttpCallManager httpCallManager;
@Inject
RequestQueue requestQueue;
private final SiteEndpoints endpoints = new SiteEndpoints() {
@Override
public String catalog(Board board) {
@ -69,12 +99,28 @@ public class Chan4 implements Site {
}
@Override
public String reply(Board board, Loadable thread) {
return "https://sys.4chan.org/" + board.code + "/post";
public String reply(Loadable loadable) {
return "https://sys.4chan.org/" + loadable.getBoard().code + "/post";
}
@Override
public String delete(Post post) {
return "https://sys.4chan.org/" + post.board.code + "/imgboard.php";
}
@Override
public String report(Post post) {
return "https://sys.4chan.org/" + post.board.code + "/imgboard.php?mode=report&no=" + post.no;
}
@Override
public String login() {
return "https://sys.4chan.org/auth";
}
};
public Chan4() {
getGraph().inject(this);
}
/**
@ -100,6 +146,9 @@ public class Chan4 implements Site {
case POST_DELETE:
// yes, with the password saved when posting.
return true;
case POST_REPORT:
// yes, with a custom url
return true;
default:
return false;
}
@ -144,7 +193,7 @@ public class Chan4 implements Site {
@Override
public void boards(final BoardsListener listener) {
getGraph().getRequestQueue().add(new Chan4BoardsRequest(this, new Response.Listener<List<Board>>() {
requestQueue.add(new Chan4BoardsRequest(this, new Response.Listener<List<Board>>() {
@Override
public void onResponse(List<Board> response) {
listener.onBoardsReceived(new Boards(response));
@ -170,4 +219,49 @@ public class Chan4 implements Site {
public ChanLoaderRequest loaderRequest(ChanLoaderRequestParams request) {
return new ChanLoaderRequest(new Chan4ReaderRequest(request));
}
@Override
public void post(Reply reply, final PostListener postListener) {
httpCallManager.makeHttpCall(new Chan4ReplyHttpCall(reply), new HttpCall.HttpCallback<Chan4ReplyHttpCall>() {
@Override
public void onHttpSuccess(Chan4ReplyHttpCall httpPost) {
postListener.onPostComplete(httpPost, httpPost.replyResponse);
}
@Override
public void onHttpFail(Chan4ReplyHttpCall httpPost, Exception e) {
postListener.onPostError(httpPost);
}
});
}
@Override
public void delete(DeleteRequest deleteRequest, final DeleteListener deleteListener) {
httpCallManager.makeHttpCall(new Chan4DeleteHttpCall(deleteRequest), new HttpCall.HttpCallback<Chan4DeleteHttpCall>() {
@Override
public void onHttpSuccess(Chan4DeleteHttpCall httpPost) {
deleteListener.onDeleteComplete(httpPost, httpPost.deleteResponse);
}
@Override
public void onHttpFail(Chan4DeleteHttpCall httpPost, Exception e) {
deleteListener.onDeleteError(httpPost);
}
});
}
@Override
public void login(LoginRequest loginRequest, final LoginListener loginListener) {
httpCallManager.makeHttpCall(new Chan4PassHttpCall(loginRequest), new HttpCall.HttpCallback<Chan4PassHttpCall>() {
@Override
public void onHttpSuccess(Chan4PassHttpCall httpCall) {
loginListener.onLoginComplete(httpCall, httpCall.loginResponse);
}
@Override
public void onHttpFail(Chan4PassHttpCall httpCall, Exception e) {
loginListener.onLoginError(httpCall);
}
});
}
}

@ -15,10 +15,11 @@
* 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.http;
package org.floens.chan.core.site.sites.chan4;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.core.model.SavedReply;
import org.floens.chan.core.site.http.DeleteRequest;
import org.floens.chan.core.site.http.DeleteResponse;
import org.floens.chan.core.site.http.HttpCall;
import org.jsoup.Jsoup;
import java.io.IOException;
@ -29,31 +30,27 @@ import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.Response;
public class DeleteHttpCall extends HttpCall {
public class Chan4DeleteHttpCall extends HttpCall {
private static final Pattern ERROR_MESSAGE = Pattern.compile("\"errmsg\"[^>]*>(.*?)<\\/span");
public boolean deleted;
public String errorMessage;
private final DeleteRequest deleteRequest;
public final DeleteResponse deleteResponse = new DeleteResponse();
private final SavedReply reply;
private final boolean onlyImageDelete;
public DeleteHttpCall(final SavedReply reply, boolean onlyImageDelete) {
this.reply = reply;
this.onlyImageDelete = onlyImageDelete;
public Chan4DeleteHttpCall(DeleteRequest deleteRequest) {
this.deleteRequest = deleteRequest;
}
@Override
public void setup(Request.Builder requestBuilder) {
FormBody.Builder formBuilder = new FormBody.Builder();
formBuilder.add(Integer.toString(reply.no), "delete");
if (onlyImageDelete) {
formBuilder.add(Integer.toString(deleteRequest.post.no), "delete");
if (deleteRequest.imageOnly) {
formBuilder.add("onlyimgdel", "on");
}
formBuilder.add("mode", "usrdel");
formBuilder.add("pwd", reply.password);
formBuilder.add("pwd", deleteRequest.savedReply.password);
requestBuilder.url(ChanUrls.getDeleteUrl(reply.board));
requestBuilder.url(deleteRequest.site.endpoints().delete(deleteRequest.post));
requestBuilder.post(formBuilder.build());
}
@ -61,9 +58,9 @@ public class DeleteHttpCall extends HttpCall {
public void process(Response response, String result) throws IOException {
Matcher errorMessageMatcher = ERROR_MESSAGE.matcher(result);
if (errorMessageMatcher.find()) {
errorMessage = Jsoup.parse(errorMessageMatcher.group(1)).body().ownText();
deleteResponse.errorMessage = Jsoup.parse(errorMessageMatcher.group(1)).body().ownText();
} else {
deleted = true;
deleteResponse.deleted = true;
}
}
}

@ -15,9 +15,11 @@
* 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.http;
package org.floens.chan.core.site.sites.chan4;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.core.site.http.HttpCall;
import org.floens.chan.core.site.http.LoginRequest;
import org.floens.chan.core.site.http.LoginResponse;
import java.io.IOException;
import java.net.HttpCookie;
@ -27,17 +29,12 @@ import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.Response;
public class PassHttpCall extends HttpCall {
public boolean success;
public String message;
public String passId;
public class Chan4PassHttpCall extends HttpCall {
private final LoginRequest loginRequest;
public final LoginResponse loginResponse = new LoginResponse();
private String token;
private String pin;
public PassHttpCall(String token, String pin) {
this.token = token;
this.pin = pin;
public Chan4PassHttpCall(LoginRequest loginRequest) {
this.loginRequest = loginRequest;
}
@Override
@ -46,10 +43,10 @@ public class PassHttpCall extends HttpCall {
formBuilder.add("act", "do_login");
formBuilder.add("id", token);
formBuilder.add("pin", pin);
formBuilder.add("id", loginRequest.user);
formBuilder.add("pin", loginRequest.pass);
requestBuilder.url(ChanUrls.getPassUrl());
requestBuilder.url(loginRequest.site.endpoints().login());
requestBuilder.post(formBuilder.build());
}
@ -59,6 +56,7 @@ public class PassHttpCall extends HttpCall {
if (result.contains("Success! Your device is now authorized")) {
authSuccess = true;
} else {
String message;
if (result.contains("Your Token must be exactly 10 characters")) {
message = "Incorrect token";
} else if (result.contains("You have left one or more fields blank")) {
@ -68,6 +66,7 @@ public class PassHttpCall extends HttpCall {
} else {
message = "Unknown error";
}
loginResponse.message = message;
}
if (authSuccess) {
@ -86,11 +85,11 @@ public class PassHttpCall extends HttpCall {
}
if (passId != null) {
this.passId = passId;
message = "Success! Your device is now authorized.";
success = true;
loginResponse.token = passId;
loginResponse.message = "Success! Your device is now authorized.";
loginResponse.success = true;
} else {
message = "Could not get pass id";
loginResponse.message = "Could not get pass id";
}
}
}

@ -15,7 +15,7 @@
* 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.loaders;
package org.floens.chan.core.site.sites.chan4;
import android.util.JsonReader;

@ -15,12 +15,14 @@
* 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.http;
package org.floens.chan.core.site.sites.chan4;
import android.text.TextUtils;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.core.model.Reply;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.http.HttpCall;
import org.floens.chan.core.site.http.ReplyResponse;
import org.floens.chan.core.site.http.Reply;
import org.jsoup.Jsoup;
import java.io.IOException;
@ -34,40 +36,34 @@ import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class ReplyHttpCall extends HttpCall {
private static final String TAG = "ReplyHttpCall";
public class Chan4ReplyHttpCall extends HttpCall {
private static final String TAG = "Chan4ReplyHttpCall";
private static final Random RANDOM = new Random();
private static final Pattern THREAD_NO_PATTERN = Pattern.compile("<!-- thread:([0-9]+),no:([0-9]+) -->");
private static final Pattern ERROR_MESSAGE = Pattern.compile("\"errmsg\"[^>]*>(.*?)<\\/span");
private static final String PROBABLY_BANNED_TEXT = "banned";
public boolean posted;
public String errorMessage;
public String text;
public String password;
public int threadNo = -1;
public int postNo = -1;
public boolean probablyBanned;
public final Reply reply;
public final ReplyResponse replyResponse = new ReplyResponse();
private final Reply reply;
public ReplyHttpCall(Reply reply) {
public Chan4ReplyHttpCall(Reply reply) {
this.reply = reply;
}
@Override
public void setup(Request.Builder requestBuilder) {
boolean thread = reply.resto >= 0;
boolean thread = reply.loadable.isThreadMode();
password = Long.toHexString(RANDOM.nextLong());
replyResponse.password = Long.toHexString(RANDOM.nextLong());
MultipartBody.Builder formBuilder = new MultipartBody.Builder();
formBuilder.setType(MultipartBody.FORM);
formBuilder.addFormDataPart("mode", "regist");
formBuilder.addFormDataPart("pwd", password);
formBuilder.addFormDataPart("pwd", replyResponse.password);
if (thread) {
formBuilder.addFormDataPart("resto", String.valueOf(reply.resto));
formBuilder.addFormDataPart("resto", String.valueOf(reply.loadable.no));
}
formBuilder.addFormDataPart("name", reply.name);
@ -79,7 +75,7 @@ public class ReplyHttpCall extends HttpCall {
formBuilder.addFormDataPart("com", reply.comment);
if (reply.captchaResponse != null) {
if (!reply.noVerification) {
if (reply.captchaChallenge != null) {
formBuilder.addFormDataPart("recaptcha_challenge_field", reply.captchaChallenge);
formBuilder.addFormDataPart("recaptcha_response_field", reply.captchaResponse);
@ -98,33 +94,32 @@ public class ReplyHttpCall extends HttpCall {
formBuilder.addFormDataPart("spoiler", "on");
}
requestBuilder.url(ChanUrls.getReplyUrl(reply.board));
Site site = reply.loadable.getSite();
requestBuilder.url(site.endpoints().reply(reply.loadable));
requestBuilder.post(formBuilder.build());
if (reply.usePass) {
if (reply.noVerification) {
requestBuilder.addHeader("Cookie", "pass_id=" + reply.passId);
}
}
@Override
public void process(Response response, String result) throws IOException {
text = result;
Matcher errorMessageMatcher = ERROR_MESSAGE.matcher(result);
if (errorMessageMatcher.find()) {
errorMessage = Jsoup.parse(errorMessageMatcher.group(1)).body().text();
probablyBanned = errorMessage.contains("banned");
replyResponse.errorMessage = Jsoup.parse(errorMessageMatcher.group(1)).body().text();
replyResponse.probablyBanned = replyResponse.errorMessage.contains(PROBABLY_BANNED_TEXT);
} else {
Matcher threadNoMatcher = THREAD_NO_PATTERN.matcher(result);
if (threadNoMatcher.find()) {
try {
threadNo = Integer.parseInt(threadNoMatcher.group(1));
postNo = Integer.parseInt(threadNoMatcher.group(2));
replyResponse.threadNo = Integer.parseInt(threadNoMatcher.group(1));
replyResponse.postNo = Integer.parseInt(threadNoMatcher.group(2));
} catch (NumberFormatException ignored) {
}
if (threadNo >= 0 && postNo >= 0) {
posted = true;
if (replyResponse.threadNo >= 0 && replyResponse.postNo >= 0) {
replyResponse.posted = true;
}
}
}

@ -15,7 +15,7 @@
* 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.loaders;
package org.floens.chan.core.site.sites.chan4;
import org.floens.chan.chan.ChanParser;
import org.floens.chan.core.database.DatabaseSavedReplyManager;

@ -26,12 +26,16 @@ import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.floens.chan.Chan;
import org.floens.chan.R;
import org.floens.chan.controller.Controller;
import org.floens.chan.core.http.PassHttpCall;
import org.floens.chan.core.http.ReplyManager;
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;
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.ui.view.CrossfadeView;
import org.floens.chan.utils.AndroidUtils;
import org.floens.chan.utils.AnimationUtils;
@ -41,10 +45,13 @@ import javax.inject.Inject;
import static org.floens.chan.Chan.getGraph;
import static org.floens.chan.utils.AndroidUtils.getString;
public class PassSettingsController extends Controller implements View.OnClickListener, ReplyManager.HttpCallback<PassHttpCall> {
public class PassSettingsController extends Controller implements View.OnClickListener, Site.LoginListener {
@Inject
ReplyManager replyManager;
@Inject
HttpCallManager httpCallManager;
private LinearLayout container;
private CrossfadeView crossfadeView;
private TextView errors;
@ -120,36 +127,37 @@ public class PassSettingsController extends Controller implements View.OnClickLi
}
@Override
public void onHttpSuccess(PassHttpCall httpPost) {
if (httpPost.success) {
authSuccess(httpPost);
public void onLoginComplete(HttpCall httpCall, LoginResponse loginResponse) {
if (loginResponse.success) {
authSuccess(loginResponse);
} else {
authFail(httpPost);
authFail(loginResponse);
}
authAfter();
}
@Override
public void onHttpFail(PassHttpCall httpPost) {
authFail(httpPost);
public void onLoginError(HttpCall httpCall) {
authFail(null);
authAfter();
}
private void authSuccess(PassHttpCall httpPost) {
private void authSuccess(LoginResponse response) {
crossfadeView.toggle(false, true);
button.setText(R.string.setting_pass_logout);
ChanSettings.passId.set(httpPost.passId);
authenticated.setText(httpPost.message);
ChanSettings.passId.set(response.token);
authenticated.setText(response.message);
((PassSettingControllerListener) previousSiblingController).onPassEnabledChanged(true);
}
private void authFail(PassHttpCall httpPost) {
if (httpPost.message == null) {
httpPost.message = getString(R.string.setting_pass_error);
private void authFail(LoginResponse response) {
String message = getString(R.string.setting_pass_error);
if (response != null && response.message != null) {
message = response.message;
}
showError(httpPost.message);
showError(message);
button.setText(R.string.setting_pass_login);
}
@ -170,7 +178,9 @@ public class PassSettingsController extends Controller implements View.OnClickLi
ChanSettings.passToken.set(inputToken.getText().toString());
ChanSettings.passPin.set(inputPin.getText().toString());
replyManager.makeHttpCall(new PassHttpCall(ChanSettings.passToken.get(), ChanSettings.passPin.get()), 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 showError(String error) {

@ -20,6 +20,7 @@ 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;
@ -27,8 +28,12 @@ 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;
public class ReportController extends Controller {
private Post post;
@ -44,18 +49,26 @@ public class ReportController extends Controller {
super.onCreate();
navigationItem.title = context.getString(R.string.report_screen, PostHelper.getTitle(post, null));
CookieManager cookieManager = CookieManager.getInstance();
cookieManager.removeAllCookie();
if (ChanSettings.passLoggedIn()) {
for (String cookie : ChanUrls.getReportCookies(ChanSettings.passId.get())) {
cookieManager.setCookie(ChanUrls.getReportDomain(), cookie);
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);
}
}
}
WebView webView = new WebView(context);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.loadUrl(ChanUrls.getReportUrl(post.boardId, post.no));
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
webView.loadUrl(url);
view = webView;
}
}

@ -21,12 +21,10 @@ import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
import org.floens.chan.Chan;
import org.floens.chan.core.http.ReplyManager;
import org.floens.chan.core.manager.ReplyManager;
import org.floens.chan.utils.IOUtils;
import org.floens.chan.utils.Logger;

@ -37,7 +37,7 @@ import android.widget.Toast;
import org.floens.chan.R;
import org.floens.chan.core.model.ChanThread;
import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Reply;
import org.floens.chan.core.site.http.Reply;
import org.floens.chan.core.presenter.ReplyPresenter;
import org.floens.chan.core.settings.ChanSettings;
import org.floens.chan.ui.activity.StartActivity;

Loading…
Cancel
Save