From 47e90037f49513b253a6b76003777f7bc5e9a84c Mon Sep 17 00:00:00 2001 From: Floens Date: Wed, 28 Jan 2015 11:37:13 +0100 Subject: [PATCH 01/14] Fix captcha image --- Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java | 2 +- docs/gcaptcha.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java b/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java index 3ac78be8..e39311df 100644 --- a/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java +++ b/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java @@ -43,7 +43,7 @@ public class ChanUrls { } public static String getCaptchaImageUrl(String challenge) { - return scheme + "://www.google.com/recaptcha/api2/payload?c=" + challenge; + return scheme + "://www.google.com/recaptcha/api2/payload?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc&c=" + challenge; } public static String getCaptchaFallback() { diff --git a/docs/gcaptcha.txt b/docs/gcaptcha.txt index 590789ea..580d6ab5 100644 --- a/docs/gcaptcha.txt +++ b/docs/gcaptcha.txt @@ -10,7 +10,7 @@ https://www.google.com/recaptcha/api/challenge?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTL contains the key 'challenge' Now load the image -https://www.google.com/recaptcha/api2/payload?c=CHALLENGE +https://www.google.com/recaptcha/api2/payload?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc&c=CHALLENGE after the user has solved the image, do a POST to From e3a925d756b7e7c9da4b8dc6ca830b36c327eca1 Mon Sep 17 00:00:00 2001 From: Floens Date: Wed, 28 Jan 2015 11:45:16 +0100 Subject: [PATCH 02/14] Update ion --- Clover/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Clover/app/build.gradle b/Clover/app/build.gradle index 385fc5ea..d117aec5 100644 --- a/Clover/app/build.gradle +++ b/Clover/app/build.gradle @@ -71,7 +71,7 @@ dependencies { compile 'com.j256.ormlite:ormlite-core:4.48' compile 'com.j256.ormlite:ormlite-android:4.48' compile 'com.android.support:support-v13:18.0.0' - compile 'com.koushikdutta.ion:ion:2.0.1' + compile 'com.koushikdutta.ion:ion:2.0.5' compile 'pl.droidsonroids.gif:android-gif-drawable:1.0.12' compile files('libs/httpclientandroidlib-1.2.1.jar') From a6cfc71de1149c4b04718b0f9857727594bcf65a Mon Sep 17 00:00:00 2001 From: Floens Date: Wed, 28 Jan 2015 11:50:57 +0100 Subject: [PATCH 03/14] Release v1.2.6 --- CHANGES.txt | 4 ++++ Clover/app/build.gradle | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 784b9266..7f7dc6db 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +New in 1.2.6 (2015-01-28) +- Fix for captcha image not loading + + New in 1.2.5 (2014-12-11) - Fix 4chan pass diff --git a/Clover/app/build.gradle b/Clover/app/build.gradle index d117aec5..339a5adb 100644 --- a/Clover/app/build.gradle +++ b/Clover/app/build.gradle @@ -8,8 +8,8 @@ android { minSdkVersion 14 targetSdkVersion 21 - versionName "v1.2.5" - versionCode 43 + versionName "v1.2.6" + versionCode 44 } compileOptions { From 08f94ed17f9514da19214bcba22bb70a92a8bd38 Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 31 Jan 2015 16:15:37 +0100 Subject: [PATCH 04/14] Swap Ion for okhttp. --- Clover/app/build.gradle | 4 +- Clover/app/proguard.cfg | 3 + .../java/org/floens/chan/ChanApplication.java | 10 - .../chan/ui/view/ThumbnailImageView.java | 14 +- .../java/org/floens/chan/utils/FileCache.java | 238 ++++++++++++++---- .../org/floens/chan/utils/ImageSaver.java | 4 +- 6 files changed, 198 insertions(+), 75 deletions(-) diff --git a/Clover/app/build.gradle b/Clover/app/build.gradle index 339a5adb..e772fb32 100644 --- a/Clover/app/build.gradle +++ b/Clover/app/build.gradle @@ -9,7 +9,7 @@ android { targetSdkVersion 21 versionName "v1.2.6" - versionCode 44 + versionCode 45 } compileOptions { @@ -71,8 +71,8 @@ dependencies { compile 'com.j256.ormlite:ormlite-core:4.48' compile 'com.j256.ormlite:ormlite-android:4.48' compile 'com.android.support:support-v13:18.0.0' - compile 'com.koushikdutta.ion:ion:2.0.5' compile 'pl.droidsonroids.gif:android-gif-drawable:1.0.12' + compile 'com.squareup.okhttp:okhttp:2.2.0' compile files('libs/httpclientandroidlib-1.2.1.jar') } diff --git a/Clover/app/proguard.cfg b/Clover/app/proguard.cfg index 7f3763cc..b1606d14 100644 --- a/Clover/app/proguard.cfg +++ b/Clover/app/proguard.cfg @@ -132,3 +132,6 @@ } -keep public class pl.droidsonroids.gif.GifIOException{*;} + +-dontwarn java.nio.** +-dontwarn org.codehaus.mojo.** diff --git a/Clover/app/src/main/java/org/floens/chan/ChanApplication.java b/Clover/app/src/main/java/org/floens/chan/ChanApplication.java index f3c5a7dd..a03f3393 100644 --- a/Clover/app/src/main/java/org/floens/chan/ChanApplication.java +++ b/Clover/app/src/main/java/org/floens/chan/ChanApplication.java @@ -25,9 +25,6 @@ import android.view.ViewConfiguration; import com.android.volley.RequestQueue; import com.android.volley.toolbox.ImageLoader; import com.android.volley.toolbox.Volley; -import com.koushikdutta.ion.Ion; -import com.koushikdutta.ion.builder.Builders; -import com.koushikdutta.ion.builder.LoadBuilder; import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.ChanPreferences; @@ -101,10 +98,6 @@ public class ChanApplication extends Application { return fileCache; } - public static LoadBuilder getIon() { - return Ion.getDefault(getInstance()).build(getInstance()); - } - public static SharedPreferences getPreferences() { return PreferenceManager.getDefaultSharedPreferences(instance); } @@ -134,9 +127,6 @@ public class ChanApplication extends Application { IconCache.createIcons(this); - Ion.getDefault(getInstance()).getCache().clear(); - Ion.getDefault(getInstance()).getCache().setMaxSize(1 * 1024 * 1024); - File cacheDir = getExternalCacheDir() != null ? getExternalCacheDir() : getCacheDir(); volleyRequestQueue = Volley.newRequestQueue(this, null, new File(cacheDir, Volley.DEFAULT_CACHE_DIR), VOLLEY_CACHE_SIZE); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java index fd9945da..03cae364 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java @@ -33,7 +33,6 @@ import android.widget.VideoView; import com.android.volley.Request; import com.android.volley.VolleyError; import com.android.volley.toolbox.ImageLoader.ImageContainer; -import com.koushikdutta.async.future.Future; import org.floens.chan.ChanApplication; import org.floens.chan.R; @@ -44,6 +43,7 @@ import org.floens.chan.utils.Utils; import java.io.File; import java.io.IOException; +import java.util.concurrent.Future; import pl.droidsonroids.gif.GifDrawable; import pl.droidsonroids.gif.GifImageView; @@ -61,7 +61,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener private boolean thumbnailNeeded = true; private Request imageRequest; - private Future ionRequest; + private Future request; private VideoView videoView; private GifDrawable gifDrawable; @@ -121,7 +121,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener } callback.setProgress(true); - ionRequest = ChanApplication.getFileCache().downloadFile(getContext(), imageUrl, new FileCache.DownloadedCallback() { + request = ChanApplication.getFileCache().downloadFile(imageUrl, new FileCache.DownloadedCallback() { @Override public void onProgress(long downloaded, long total, boolean done) { if (done) { @@ -177,7 +177,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener } callback.setProgress(true); - ionRequest = ChanApplication.getFileCache().downloadFile(getContext(), gifUrl, new FileCache.DownloadedCallback() { + request = ChanApplication.getFileCache().downloadFile(gifUrl, new FileCache.DownloadedCallback() { @Override public void onProgress(long downloaded, long total, boolean done) { if (done) { @@ -228,7 +228,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener public void setVideo(String videoUrl) { callback.setProgress(true); - ionRequest = ChanApplication.getFileCache().downloadFile(getContext(), videoUrl, new FileCache.DownloadedCallback() { + request = ChanApplication.getFileCache().downloadFile(videoUrl, new FileCache.DownloadedCallback() { @Override public void onProgress(long downloaded, long total, boolean done) { if (done) { @@ -327,8 +327,8 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener imageRequest = null; } - if (ionRequest != null) { - ionRequest.cancel(true); + if (request != null) { + request.cancel(true); } } diff --git a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java b/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java index 3ea6ee97..554d67a3 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java @@ -1,21 +1,32 @@ package org.floens.chan.utils; -import android.content.Context; import android.util.Log; -import com.koushikdutta.async.future.Future; -import com.koushikdutta.async.future.FutureCallback; -import com.koushikdutta.ion.ProgressCallback; -import com.koushikdutta.ion.Response; - -import org.floens.chan.ChanApplication; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import com.squareup.okhttp.ResponseBody; +import com.squareup.okhttp.internal.Util; +import java.io.BufferedOutputStream; +import java.io.Closeable; import java.io.File; -import java.util.concurrent.CancellationException; +import java.io.FileOutputStream; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import okio.BufferedSource; public class FileCache { private static final String TAG = "FileCache"; + private static final ExecutorService executor = Executors.newFixedThreadPool(2); + + private OkHttpClient httpClient; + private final File directory; private final long maxSize; @@ -25,6 +36,8 @@ public class FileCache { this.directory = directory; this.maxSize = maxSize; + httpClient = new OkHttpClient(); + makeDir(); calculateSize(); } @@ -47,57 +60,16 @@ public class FileCache { return file.delete(); } - public Future> downloadFile(Context context, String url, final DownloadedCallback callback) { - File file = get(url); + public Future downloadFile(final String urlString, final DownloadedCallback callback) { + File file = get(urlString); if (file.exists()) { file.setLastModified(Time.get()); callback.onProgress(0, 0, true); callback.onSuccess(file); return null; } else { - return ChanApplication.getIon() - .load(url) - .progress(new ProgressCallback() { - @Override - public void onProgress(final long downloaded, final long total) { - Utils.runOnUiThread(new Runnable() { - @Override - public void run() { - callback.onProgress(downloaded, total, false); - } - }); - } - }) - .write(file) - .withResponse() - .setCallback(new FutureCallback>() { - @Override - public void onCompleted(Exception e, Response result) { - callback.onProgress(0, 0, true); - - if (result != null && result.getHeaders() != null && result.getHeaders().code() / 100 != 2) { - if (result.getResult() != null) { - delete(result.getResult()); - } - callback.onFail(true); - return; - } - - if (e != null && !(e instanceof CancellationException)) { - e.printStackTrace(); - if (result != null && result.getResult() != null) { - delete(result.getResult()); - } - callback.onFail(false); - return; - } - - if (result != null && result.getResult() != null) { - put(result.getResult()); - callback.onSuccess(result.getResult()); - } - } - }); + FileCacheDownloader downloader = new FileCacheDownloader(this, urlString, file, callback); + return executor.submit(downloader); } } @@ -163,4 +135,164 @@ public class FileCache { public void onFail(boolean notFound); } + + private static class FileCacheDownloader implements Runnable { + private final FileCache fileCache; + private final String url; + private final File output; + private final DownloadedCallback callback; + private boolean cancelled = false; + + private Closeable downloadInput; + private Closeable downloadOutput; + + public FileCacheDownloader(FileCache fileCache, String url, File output, DownloadedCallback callback) { + this.fileCache = fileCache; + this.url = url; + this.output = output; + this.callback = callback; + } + + public void run() { + try { + execute(); + } catch (InterruptedIOException | InterruptedException e) { + cancelDueToCancellation(e); + } catch (Exception e) { + cancelDueToException(e); + } + } + + private void cancelDueToException(Exception e) { + if (cancelled) return; + cancelled = true; + + Log.w(TAG, "IOException downloading file", e); + + purgeOutput(); + closeStreams(); + + post(new Runnable() { + @Override + public void run() { + callback.onProgress(0, 0, true); + callback.onFail(false); + } + }); + } + + private void cancelDueToHttpError(final int code) { + if (cancelled) return; + cancelled = true; + + Log.w(TAG, "Cancel due to http error, code: " + code); + + purgeOutput(); + closeStreams(); + + post(new Runnable() { + @Override + public void run() { + callback.onProgress(0, 0, true); + callback.onFail(code == 404); + } + }); + } + + private void cancelDueToCancellation(Exception e) { + if (cancelled) return; + cancelled = true; + + Log.d(TAG, "Cancel due to cancellation"); + + purgeOutput(); + closeStreams(); + + // No callback + } + + private void closeStreams() { + Util.closeQuietly(downloadInput); + Util.closeQuietly(downloadOutput); + } + + private void purgeOutput() { + if (output.exists()) { + if (!output.delete()) { + Log.w(TAG, "Could not delete the file in purgeOutput"); + } + } + } + + private long progressDownloaded; + private long progressTotal; + private boolean progressDone; + private final Runnable progressRunnable = new Runnable() { + @Override + public void run() { + callback.onProgress(progressDownloaded, progressTotal, progressDone); + } + }; + + private void progress(long downloaded, long total, boolean done) { + progressDownloaded = downloaded; + progressTotal = total; + progressDone = done; + post(progressRunnable); + } + + private void success() { + fileCache.put(output); + + post(new Runnable() { + @Override + public void run() { + callback.onProgress(0, 0, true); + callback.onSuccess(output); + } + }); + } + + private void post(Runnable runnable) { + Utils.runOnUiThread(runnable); + } + + private void execute() throws Exception { + Request request = new Request.Builder().url(url).build(); + + Response response = fileCache.httpClient.newCall(request).execute(); + if (!response.isSuccessful()) { + cancelDueToHttpError(response.code()); + return; + } + + ResponseBody body = response.body(); + long contentLength = body.contentLength(); + BufferedSource source = body.source(); + OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(output)); + + downloadInput = source; + downloadOutput = outputStream; + + int read; + long total = 0; + long totalLast = 0; + byte[] buffer = new byte[4096]; + while ((read = source.read(buffer)) != -1) { + outputStream.write(buffer, 0, read); + total += read; + + if (total >= totalLast + 16384) { + totalLast = total; + progress(total, contentLength, false); + } + + if (Thread.currentThread().isInterrupted()) throw new InterruptedIOException(); + } + + closeStreams(); + + success(); + } + } } diff --git a/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java b/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java index b9e9c526..59e4afd4 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/ImageSaver.java @@ -28,8 +28,6 @@ import android.media.MediaScannerConnection; import android.net.Uri; import android.widget.Toast; -import com.koushikdutta.async.future.Future; - import org.floens.chan.ChanApplication; import org.floens.chan.R; import org.floens.chan.core.ChanPreferences; @@ -67,7 +65,7 @@ public class ImageSaver { } public void saveImage(final Context context, String imageUrl, final String name, final String extension, final boolean share) { - Future ionRequest = ChanApplication.getFileCache().downloadFile(context, imageUrl, new FileCache.DownloadedCallback() { + ChanApplication.getFileCache().downloadFile(imageUrl, new FileCache.DownloadedCallback() { @Override @SuppressWarnings("deprecation") public void onProgress(long downloaded, long total, boolean done) { From 76e14bd5d175f68c6d2eca109eeeb7bc3562c859 Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 31 Jan 2015 19:08:35 +0100 Subject: [PATCH 05/14] Proper closing of okhttp streams --- .../chan/ui/view/ThumbnailImageView.java | 2 +- .../java/org/floens/chan/utils/FileCache.java | 33 +++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java index 03cae364..13395a3f 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/view/ThumbnailImageView.java @@ -312,7 +312,7 @@ public class ThumbnailImageView extends LoadView implements View.OnClickListener } public void onNotFoundError() { - Toast.makeText(getContext(), R.string.image_not_found, Toast.LENGTH_LONG).show(); + Toast.makeText(getContext(), R.string.image_not_found, Toast.LENGTH_SHORT).show(); callback.setProgress(false); } diff --git a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java b/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java index 554d67a3..433ff2de 100644 --- a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java +++ b/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java @@ -2,6 +2,7 @@ package org.floens.chan.utils; import android.util.Log; +import com.squareup.okhttp.Call; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; @@ -145,6 +146,8 @@ public class FileCache { private Closeable downloadInput; private Closeable downloadOutput; + private Call call; + private ResponseBody body; public FileCacheDownloader(FileCache fileCache, String url, File output, DownloadedCallback callback) { this.fileCache = fileCache; @@ -158,9 +161,14 @@ public class FileCache { execute(); } catch (InterruptedIOException | InterruptedException e) { cancelDueToCancellation(e); + return; } catch (Exception e) { cancelDueToException(e); + return; } + + finish(); + success(); } private void cancelDueToException(Exception e) { @@ -170,7 +178,7 @@ public class FileCache { Log.w(TAG, "IOException downloading file", e); purgeOutput(); - closeStreams(); + finish(); post(new Runnable() { @Override @@ -188,7 +196,7 @@ public class FileCache { Log.w(TAG, "Cancel due to http error, code: " + code); purgeOutput(); - closeStreams(); + finish(); post(new Runnable() { @Override @@ -206,14 +214,22 @@ public class FileCache { Log.d(TAG, "Cancel due to cancellation"); purgeOutput(); - closeStreams(); + finish(); // No callback } - private void closeStreams() { + private void finish() { Util.closeQuietly(downloadInput); Util.closeQuietly(downloadOutput); + + if (call != null) { + call.cancel(); + } + + if (body != null) { + Util.closeQuietly(body); + } } private void purgeOutput() { @@ -260,13 +276,14 @@ public class FileCache { private void execute() throws Exception { Request request = new Request.Builder().url(url).build(); - Response response = fileCache.httpClient.newCall(request).execute(); + call = fileCache.httpClient.newCall(request); + Response response = call.execute(); if (!response.isSuccessful()) { cancelDueToHttpError(response.code()); return; } - ResponseBody body = response.body(); + body = response.body(); long contentLength = body.contentLength(); BufferedSource source = body.source(); OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(output)); @@ -289,10 +306,6 @@ public class FileCache { if (Thread.currentThread().isInterrupted()) throw new InterruptedIOException(); } - - closeStreams(); - - success(); } } } From c9a522c24ea0f3894cee155bafa6648c0c6a501e Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 31 Jan 2015 19:21:53 +0100 Subject: [PATCH 06/14] Update licenses --- Clover/app/src/main/assets/html/licenses.html | 72 +++++++------------ 1 file changed, 24 insertions(+), 48 deletions(-) diff --git a/Clover/app/src/main/assets/html/licenses.html b/Clover/app/src/main/assets/html/licenses.html index 648d6b02..d5e62697 100644 --- a/Clover/app/src/main/assets/html/licenses.html +++ b/Clover/app/src/main/assets/html/licenses.html @@ -37,34 +37,17 @@ limitations under the License.
-

Jsoup

-
-        
-The jsoup code-base (include source and compiled packages) are distributed under the open source MIT license as described below.
-
-The MIT License
-Copyright © 2009 - 2013 Jonathan Hedley (jonathan@hedley.net)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-        
-    
-
- -

AndroidFloatLabel from Weddingparty

- https://github.com/weddingparty/AndroidFloatLabel +

subsampling-scale-image-view

+ https://github.com/davemorrissey/subsampling-scale-image-view
         
-Copyright (C) 2014 AndroidFloatLabel team
+Copyright 2014 David Morrissey
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
-  http://www.apache.org/licenses/LICENSE-2.0
+   http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
@@ -75,17 +58,14 @@ limitations under the License.
     

-

This software includes several Android classes from DashClock

- https://code.google.com/p/dashclock/ +

Square okhttp

         
-Copyright 2013 Google Inc.
-
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
- http://www.apache.org/licenses/LICENSE-2.0
+   http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
@@ -96,41 +76,34 @@ limitations under the License.
     

-

DragSortListView

- https://github.com/bauerca/drag-sort-listview +

Jsoup

         
-A subclass of the Android ListView component that enables drag
-and drop re-ordering of list items.
+The jsoup code-base (include source and compiled packages) are distributed under the open source MIT license as described below.
 
-Copyright 2012 Carl Bauer
+The MIT License
+Copyright © 2009 - 2013 Jonathan Hedley (jonathan@hedley.net)
 
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
-    http://www.apache.org/licenses/LICENSE-2.0
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     

-

Ion

- https://github.com/koush/ion +

This software includes several Android classes from DashClock

+ https://code.google.com/p/dashclock/
         
-Copyright 2013 Koushik Dutta
+Copyright 2013 Google Inc.
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
-   http://www.apache.org/licenses/LICENSE-2.0
+ http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
@@ -141,17 +114,20 @@ limitations under the License.
     

-

subsampling-scale-image-view

- https://github.com/davemorrissey/subsampling-scale-image-view +

DragSortListView

+ https://github.com/bauerca/drag-sort-listview
         
-Copyright 2014 David Morrissey
+A subclass of the Android ListView component that enables drag
+and drop re-ordering of list items.
+
+Copyright 2012 Carl Bauer
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
 
-   http://www.apache.org/licenses/LICENSE-2.0
+    http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,

From 1de9ee42cf83d02da751f20f7e31d440115a4d06 Mon Sep 17 00:00:00 2001
From: Floens 
Date: Sat, 31 Jan 2015 20:16:44 +0100
Subject: [PATCH 07/14] Release v1.2.7

---
 CHANGES.txt             | 4 ++++
 Clover/app/build.gradle | 6 +++---
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 7f7dc6db..c6eccc1b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,7 @@
+New in 1.2.7 (2015-01-31)
+- Fix some image loading issues
+
+
 New in 1.2.6 (2015-01-28)
 - Fix for captcha image not loading
 
diff --git a/Clover/app/build.gradle b/Clover/app/build.gradle
index e772fb32..49abb8ca 100644
--- a/Clover/app/build.gradle
+++ b/Clover/app/build.gradle
@@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
 
 android {
     compileSdkVersion 21
-    buildToolsVersion "21.1.1"
+    buildToolsVersion "21.1.2"
 
     defaultConfig {
         minSdkVersion 14
         targetSdkVersion 21
 
-        versionName "v1.2.6"
-        versionCode 45
+        versionName "v1.2.7"
+        versionCode 46
     }
 
     compileOptions {

From 21a5b4ba681390dbbb3202355ed51afc8fc53e08 Mon Sep 17 00:00:00 2001
From: Floens 
Date: Fri, 6 Feb 2015 13:03:56 +0100
Subject: [PATCH 08/14] Fix some image loading issues.

---
 .../java/org/floens/chan/utils/FileCache.java | 43 +++++++++----------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java b/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java
index 433ff2de..7e4c00be 100644
--- a/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java
+++ b/Clover/app/src/main/java/org/floens/chan/utils/FileCache.java
@@ -161,14 +161,11 @@ public class FileCache {
                 execute();
             } catch (InterruptedIOException | InterruptedException e) {
                 cancelDueToCancellation(e);
-                return;
             } catch (Exception e) {
                 cancelDueToException(e);
-                return;
+            } finally {
+                finish();
             }
-
-            finish();
-            success();
         }
 
         private void cancelDueToException(Exception e) {
@@ -178,7 +175,6 @@ public class FileCache {
             Log.w(TAG, "IOException downloading file", e);
 
             purgeOutput();
-            finish();
 
             post(new Runnable() {
                 @Override
@@ -196,7 +192,6 @@ public class FileCache {
             Log.w(TAG, "Cancel due to http error, code: " + code);
 
             purgeOutput();
-            finish();
 
             post(new Runnable() {
                 @Override
@@ -214,21 +209,35 @@ public class FileCache {
             Log.d(TAG, "Cancel due to cancellation");
 
             purgeOutput();
-            finish();
 
             // No callback
         }
 
+        private void success() {
+            fileCache.put(output);
+
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    callback.onProgress(0, 0, true);
+                    callback.onSuccess(output);
+                }
+            });
+            call = null;
+        }
+
         private void finish() {
             Util.closeQuietly(downloadInput);
             Util.closeQuietly(downloadOutput);
 
             if (call != null) {
                 call.cancel();
+                call = null;
             }
 
             if (body != null) {
                 Util.closeQuietly(body);
+                body = null;
             }
         }
 
@@ -257,18 +266,6 @@ public class FileCache {
             post(progressRunnable);
         }
 
-        private void success() {
-            fileCache.put(output);
-
-            post(new Runnable() {
-                @Override
-                public void run() {
-                    callback.onProgress(0, 0, true);
-                    callback.onSuccess(output);
-                }
-            });
-        }
-
         private void post(Runnable runnable) {
             Utils.runOnUiThread(runnable);
         }
@@ -303,9 +300,11 @@ public class FileCache {
                     totalLast = total;
                     progress(total, contentLength, false);
                 }
-
-                if (Thread.currentThread().isInterrupted()) throw new InterruptedIOException();
             }
+
+            if (Thread.currentThread().isInterrupted()) throw new InterruptedIOException();
+
+            success();
         }
     }
 }

From 47ec05b2e40244726690b030f983751e0674d4ca Mon Sep 17 00:00:00 2001
From: Floens 
Date: Fri, 6 Feb 2015 13:22:14 +0100
Subject: [PATCH 09/14] Fix captcha

---
 .../java/org/floens/chan/chan/ChanUrls.java   |   8 +-
 .../chan/core/manager/ReplyManager.java       |  75 ++++++++----
 .../chan/ui/fragment/ReplyFragment.java       |  42 +++----
 docs/gcaptcha.txt                             | 110 ++++++++++++++++--
 4 files changed, 173 insertions(+), 62 deletions(-)

diff --git a/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java b/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java
index e39311df..2b640b7c 100644
--- a/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java
+++ b/Clover/app/src/main/java/org/floens/chan/chan/ChanUrls.java
@@ -38,12 +38,8 @@ public class ChanUrls {
         return scheme + "://a.4cdn.org/" + board + "/thread/" + no + ".json";
     }
 
-    public static String getCaptchaChallengeUrl() {
-        return scheme + "://www.google.com/recaptcha/api/challenge?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc";
-    }
-
-    public static String getCaptchaImageUrl(String challenge) {
-        return scheme + "://www.google.com/recaptcha/api2/payload?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc&c=" + challenge;
+    public static String getCaptchaDomain() {
+        return scheme + "://www.google.com/";
     }
 
     public static String getCaptchaFallback() {
diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java
index f0c4adbe..d478a491 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java
@@ -19,6 +19,7 @@ package org.floens.chan.core.manager;
 
 import android.content.Context;
 import android.content.Intent;
+import android.text.TextUtils;
 
 import org.floens.chan.ChanApplication;
 import org.floens.chan.R;
@@ -31,6 +32,7 @@ import org.floens.chan.utils.Logger;
 import org.floens.chan.utils.Utils;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
 import org.jsoup.select.Elements;
 
 import java.io.File;
@@ -60,7 +62,6 @@ import ch.boye.httpclientandroidlib.util.EntityUtils;
 public class ReplyManager {
     private static final String TAG = "ReplyManager";
 
-    private static final Pattern challengePattern = Pattern.compile("challenge.?:.?'([\\w-]+)'");
     private static final Pattern responsePattern = Pattern.compile("");
     private static final int POST_TIMEOUT = 10000;
 
@@ -170,22 +171,6 @@ public class ReplyManager {
         public abstract void onFileLoading();
     }
 
-    /**
-     * Get the CAPTCHA challenge hash from an JSON response.
-     *
-     * @param total The total response from the server
-     * @return The pattern, or null when none was found.
-     */
-    public static String getChallenge(String total) {
-        Matcher matcher = challengePattern.matcher(total);
-
-        if (matcher.find() && matcher.groupCount() == 1) {
-            return matcher.group(1);
-        } else {
-            return null;
-        }
-    }
-
     public void sendPass(Pass pass, final PassListener listener) {
         Logger.i(TAG, "Sending pass login request");
 
@@ -336,6 +321,49 @@ public class ReplyManager {
         public String responseData = "";
     }
 
+    public void getCaptchaChallenge(final CaptchaChallengeListener listener, String reuseHtml) {
+        HttpPost httpPost = new HttpPost(ChanUrls.getCaptchaFallback());
+
+        HttpPostSendListener postListener = new HttpPostSendListener() {
+            @Override
+            public void onResponse(String responseString, HttpClient client, HttpResponse response) {
+                if (responseString != null) {
+                    Document document = Jsoup.parseBodyFragment(responseString, ChanUrls.getCaptchaDomain());
+                    Elements images = document.select("div.fbc-challenge img");
+                    String imageUrl = images.first() == null ? "" : images.first().absUrl("src");
+
+                    Elements inputs = document.select("div.fbc-challenge input");
+                    String challenge = "";
+                    for (Element input : inputs) {
+                        if (input.attr("name").equals("c")) {
+                            challenge = input.attr("value");
+                            break;
+                        }
+                    }
+
+                    if (!TextUtils.isEmpty(imageUrl) && !TextUtils.isEmpty(challenge)) {
+                        listener.onChallenge(imageUrl, challenge);
+                        return;
+                    }
+                }
+                listener.onError();
+            }
+        };
+
+        if (TextUtils.isEmpty(reuseHtml)) {
+            sendHttpPost(httpPost, postListener);
+        } else {
+            Logger.i(TAG, "Reusing html " + reuseHtml);
+            postListener.onResponse(reuseHtml, null, null);
+        }
+    }
+
+    public interface CaptchaChallengeListener {
+        public void onChallenge(String imageUrl, String challenge);
+
+        public void onError();
+    }
+
     private void getCaptchaHash(final CaptchaHashListener listener, String challenge, String response) {
         HttpPost httpPost = new HttpPost(ChanUrls.getCaptchaFallback());
 
@@ -354,17 +382,17 @@ public class ReplyManager {
                     Elements verificationToken = document.select("div.fbc-verification-token textarea");
                     String hash = verificationToken.text();
                     if (hash.length() > 0) {
-                        listener.onHash(hash);
+                        listener.onHash(hash, responseString);
                         return;
                     }
                 }
-                listener.onHash(null);
+                listener.onHash(null, responseString);
             }
         });
     }
 
     private interface CaptchaHashListener {
-        public void onHash(String hash);
+        public void onHash(String hash, String html);
     }
 
     /**
@@ -379,12 +407,13 @@ public class ReplyManager {
 
         CaptchaHashListener captchaHashListener = new CaptchaHashListener() {
             @Override
-            public void onHash(String captchaHash) {
+            public void onHash(String captchaHash, String captchaHtml) {
                 if (captchaHash == null && !reply.usePass) {
                     // Could not find a hash in the response html
                     ReplyResponse e = new ReplyResponse();
                     e.isUserError = true;
                     e.isCaptchaError = true;
+                    e.captchaHtml = captchaHtml;
                     listener.onResponse(e);
                     return;
                 }
@@ -484,7 +513,7 @@ public class ReplyManager {
         };
 
         if (reply.usePass) {
-            captchaHashListener.onHash(null);
+            captchaHashListener.onHash(null, null);
         } else {
             getCaptchaHash(captchaHashListener, reply.captchaChallenge, reply.captchaResponse);
         }
@@ -535,6 +564,8 @@ public class ReplyManager {
          * The thread no the post has
          */
         public int threadNo = -1;
+
+        public String captchaHtml;
     }
 
     /**
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java
index 9a223eae..313d734c 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java
@@ -44,15 +44,10 @@ import android.widget.TextView;
 import android.widget.Toast;
 import android.widget.ViewFlipper;
 
-import com.android.volley.Request.Method;
-import com.android.volley.Response;
-import com.android.volley.VolleyError;
 import com.android.volley.toolbox.NetworkImageView;
-import com.android.volley.toolbox.StringRequest;
 
 import org.floens.chan.ChanApplication;
 import org.floens.chan.R;
-import org.floens.chan.chan.ChanUrls;
 import org.floens.chan.core.ChanPreferences;
 import org.floens.chan.core.manager.ReplyManager;
 import org.floens.chan.core.manager.ReplyManager.ReplyResponse;
@@ -209,7 +204,7 @@ public class ReplyFragment extends DialogFragment {
             });
             showCommentCount();
 
-            getCaptcha();
+            getCaptcha(null);
         } else {
             Logger.e(TAG, "Loadable in ReplyFragment was null");
             closeReply();
@@ -268,7 +263,7 @@ public class ReplyFragment extends DialogFragment {
         captchaContainer.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
-                getCaptcha();
+                getCaptcha(null);
             }
         });
         captchaInput = (TextView) container.findViewById(R.id.reply_captcha);
@@ -519,7 +514,7 @@ public class ReplyFragment extends DialogFragment {
         loadView.setView(text);
     }
 
-    private void getCaptcha() {
+    private void getCaptcha(String reuseHtml) {
         if (gettingCaptcha)
             return;
         gettingCaptcha = true;
@@ -527,29 +522,22 @@ public class ReplyFragment extends DialogFragment {
         captchaContainer.setView(null);
         captchaInput.setText("");
 
-        String url = ChanUrls.getCaptchaChallengeUrl();
-
-        ChanApplication.getVolleyRequestQueue().add(new StringRequest(Method.GET, url, new Response.Listener() {
+        ChanApplication.getReplyManager().getCaptchaChallenge(new ReplyManager.CaptchaChallengeListener() {
             @Override
-            public void onResponse(String result) {
-                if (context != null) {
-                    String challenge = ReplyManager.getChallenge(result);
-                    if (challenge != null) {
-                        captchaChallenge = challenge;
-                        String imageUrl = ChanUrls.getCaptchaImageUrl(challenge);
+            public void onChallenge(String imageUrl, String challenge) {
+                gettingCaptcha = false;
 
-                        NetworkImageView captchaImage = new NetworkImageView(context);
-                        captchaImage.setImageUrl(imageUrl, ChanApplication.getVolleyImageLoader());
-                        captchaContainer.setView(captchaImage);
+                if (context != null) {
+                    captchaChallenge = challenge;
 
-                        gettingCaptcha = false;
-                    }
+                    NetworkImageView captchaImage = new NetworkImageView(context);
+                    captchaImage.setImageUrl(imageUrl, ChanApplication.getVolleyImageLoader());
+                    captchaContainer.setView(captchaImage);
                 }
             }
-        }, new Response.ErrorListener() {
+
             @Override
-            public void onErrorResponse(VolleyError error) {
-                error.printStackTrace();
+            public void onError() {
                 gettingCaptcha = false;
 
                 if (context != null) {
@@ -559,7 +547,7 @@ public class ReplyFragment extends DialogFragment {
                     captchaContainer.setView(text);
                 }
             }
-        }));
+        }, reuseHtml);
     }
 
     /**
@@ -621,7 +609,7 @@ public class ReplyFragment extends DialogFragment {
             cancelButton.setEnabled(true);
             setClosable(true);
             flipPage(1);
-            getCaptcha();
+            getCaptcha(response.captchaHtml);
             captchaInput.setText("");
         } else if (response.isSuccessful) {
             shouldSaveDraft = false;
diff --git a/docs/gcaptcha.txt b/docs/gcaptcha.txt
index 580d6ab5..c435480b 100644
--- a/docs/gcaptcha.txt
+++ b/docs/gcaptcha.txt
@@ -7,25 +7,121 @@ https://www.google.com/recaptcha/api/fallback?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLV
 Put this in an iframe and when the user has successfully filled in the captcha the user is told to copy paste the key into the real website field (outside the iframe, g-captcha-response)
 
 https://www.google.com/recaptcha/api/challenge?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc
-contains the key 'challenge'
-
-Now load the image
-https://www.google.com/recaptcha/api2/payload?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc&c=CHALLENGE
+contains an image and and a field named "c" with the challenge
 
 after the user has solved the image, do a POST to
 
 https://www.google.com/recaptcha/api/fallback?k=6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc
 POST:
-c = CHALLENGE
-response = USER_RESPONSE
+c = the challenge given
+response = text response from the user
 
-You'll have to get hash inside the textarea of div.fbc-verification-token
+Next if the captcha was solved, get the hash inside the textarea of div.fbc-verification-token
+If the textarea isn't present, the captcha wasn't solved correctly you'll reuse the received html.
 
 next send off the reply to 4chan
 POST:
 g-captcha-response: HASH
 
 
+Initial HTML:
+
+
+
+    
+        
+        reCAPTCHA-uitdaging
+        
+    
+    
+        
+
+
+ +
+
+
+
+ +
+ +
+
+ +
+
+ reCAPTCHA-uitdagingsafbeelding +
+
+ +
+
+
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+
+
+ +
+
+ + +Copy-paste code HTML: + + + + + reCAPTCHA-uitdaging + + + +
+
+
+ +
+
+
Kopieëer deze code
+
+ +
+
Deze code is 2 minuten geldig
+
+
+
Plak de code hier
+
+ +
+
+ + From c14b22f1c344899925af6943c6cec02c147d797d Mon Sep 17 00:00:00 2001 From: Floens Date: Fri, 6 Feb 2015 13:28:44 +0100 Subject: [PATCH 10/14] Release v1.2.8 --- CHANGES.txt | 4 ++++ Clover/app/build.gradle | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index c6eccc1b..eafb5425 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +New in 1.2.8 (2015-02-06) +- Fix captcha not working + + New in 1.2.7 (2015-01-31) - Fix some image loading issues diff --git a/Clover/app/build.gradle b/Clover/app/build.gradle index 49abb8ca..abf6edb4 100644 --- a/Clover/app/build.gradle +++ b/Clover/app/build.gradle @@ -8,8 +8,8 @@ android { minSdkVersion 14 targetSdkVersion 21 - versionName "v1.2.7" - versionCode 46 + versionName "v1.2.8" + versionCode 47 } compileOptions { From b45db074ccf08d4d3688eda8c1123d9720e46928 Mon Sep 17 00:00:00 2001 From: Floens Date: Fri, 6 Feb 2015 15:39:21 +0100 Subject: [PATCH 11/14] Remove debug line. --- .../src/main/java/org/floens/chan/core/manager/ReplyManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java index d478a491..6f4d1ed5 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java @@ -353,7 +353,6 @@ public class ReplyManager { if (TextUtils.isEmpty(reuseHtml)) { sendHttpPost(httpPost, postListener); } else { - Logger.i(TAG, "Reusing html " + reuseHtml); postListener.onResponse(reuseHtml, null, null); } } From c37c1b77ae424bcc19ad679a87d61c7c12d4e539 Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 7 Feb 2015 01:15:45 +0100 Subject: [PATCH 12/14] Set "Android" as user agent when gettings captchas. Don't reuse html. --- .../chan/core/manager/ReplyManager.java | 22 +++++++------------ .../chan/ui/fragment/ReplyFragment.java | 10 ++++----- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java index 6f4d1ed5..e6f4efa7 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/manager/ReplyManager.java @@ -321,8 +321,9 @@ public class ReplyManager { public String responseData = ""; } - public void getCaptchaChallenge(final CaptchaChallengeListener listener, String reuseHtml) { + public void getCaptchaChallenge(final CaptchaChallengeListener listener) { HttpPost httpPost = new HttpPost(ChanUrls.getCaptchaFallback()); + httpPost.addHeader("User-Agent", "Android"); HttpPostSendListener postListener = new HttpPostSendListener() { @Override @@ -350,11 +351,7 @@ public class ReplyManager { } }; - if (TextUtils.isEmpty(reuseHtml)) { - sendHttpPost(httpPost, postListener); - } else { - postListener.onResponse(reuseHtml, null, null); - } + sendHttpPost(httpPost, postListener); } public interface CaptchaChallengeListener { @@ -381,17 +378,17 @@ public class ReplyManager { Elements verificationToken = document.select("div.fbc-verification-token textarea"); String hash = verificationToken.text(); if (hash.length() > 0) { - listener.onHash(hash, responseString); + listener.onHash(hash); return; } } - listener.onHash(null, responseString); + listener.onHash(null); } }); } private interface CaptchaHashListener { - public void onHash(String hash, String html); + public void onHash(String hash); } /** @@ -406,13 +403,12 @@ public class ReplyManager { CaptchaHashListener captchaHashListener = new CaptchaHashListener() { @Override - public void onHash(String captchaHash, String captchaHtml) { + public void onHash(String captchaHash) { if (captchaHash == null && !reply.usePass) { // Could not find a hash in the response html ReplyResponse e = new ReplyResponse(); e.isUserError = true; e.isCaptchaError = true; - e.captchaHtml = captchaHtml; listener.onResponse(e); return; } @@ -512,7 +508,7 @@ public class ReplyManager { }; if (reply.usePass) { - captchaHashListener.onHash(null, null); + captchaHashListener.onHash(null); } else { getCaptchaHash(captchaHashListener, reply.captchaChallenge, reply.captchaResponse); } @@ -563,8 +559,6 @@ public class ReplyManager { * The thread no the post has */ public int threadNo = -1; - - public String captchaHtml; } /** diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java index 313d734c..7b695252 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java @@ -204,7 +204,7 @@ public class ReplyFragment extends DialogFragment { }); showCommentCount(); - getCaptcha(null); + getCaptcha(); } else { Logger.e(TAG, "Loadable in ReplyFragment was null"); closeReply(); @@ -263,7 +263,7 @@ public class ReplyFragment extends DialogFragment { captchaContainer.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { - getCaptcha(null); + getCaptcha(); } }); captchaInput = (TextView) container.findViewById(R.id.reply_captcha); @@ -514,7 +514,7 @@ public class ReplyFragment extends DialogFragment { loadView.setView(text); } - private void getCaptcha(String reuseHtml) { + private void getCaptcha() { if (gettingCaptcha) return; gettingCaptcha = true; @@ -547,7 +547,7 @@ public class ReplyFragment extends DialogFragment { captchaContainer.setView(text); } } - }, reuseHtml); + }); } /** @@ -609,7 +609,7 @@ public class ReplyFragment extends DialogFragment { cancelButton.setEnabled(true); setClosable(true); flipPage(1); - getCaptcha(response.captchaHtml); + getCaptcha(); captchaInput.setText(""); } else if (response.isSuccessful) { shouldSaveDraft = false; From e6a677184841fa5f2d781c9271c284ea823083d0 Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 7 Feb 2015 01:25:08 +0100 Subject: [PATCH 13/14] Don't show "Using pass" screen, skip directly to submit. --- .../chan/ui/fragment/ReplyFragment.java | 29 ++++++++++--------- Clover/app/src/main/res/values/strings.xml | 1 - 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java index 7b695252..c56fe1e5 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ReplyFragment.java @@ -74,6 +74,7 @@ public class ReplyFragment extends DialogFragment { private final Reply draft = new Reply(); private boolean shouldSaveDraft = true; + private boolean gotInitialCaptcha = false; private boolean gettingCaptcha = false; private String captchaChallenge = ""; @@ -203,8 +204,6 @@ public class ReplyFragment extends DialogFragment { } }); showCommentCount(); - - getCaptcha(); } else { Logger.e(TAG, "Loadable in ReplyFragment was null"); closeReply(); @@ -268,12 +267,6 @@ public class ReplyFragment extends DialogFragment { }); captchaInput = (TextView) container.findViewById(R.id.reply_captcha); - if (ChanPreferences.getPassEnabled()) { - ((TextView) container.findViewById(R.id.reply_captcha_text)).setText(R.string.pass_using); - container.findViewById(R.id.reply_captcha_container).setVisibility(View.GONE); - container.findViewById(R.id.reply_captcha).setVisibility(View.GONE); - } - cancelButton = (Button) container.findViewById(R.id.reply_cancel); cancelButton.setOnClickListener(new OnClickListener() { @Override @@ -313,11 +306,11 @@ public class ReplyFragment extends DialogFragment { submitButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { - if (page == 0) { - flipPage(1); - } else if (page == 1) { + if (page == 1 || ChanPreferences.getPassEnabled()) { flipPage(2); submit(); + } else { + flipPage(1); } } }); @@ -405,12 +398,11 @@ public class ReplyFragment extends DialogFragment { if (flipBack) { flipper.setInAnimation(ViewFlipperAnimations.BACK_IN); flipper.setOutAnimation(ViewFlipperAnimations.BACK_OUT); - flipper.showPrevious(); } else { flipper.setInAnimation(ViewFlipperAnimations.NEXT_IN); flipper.setOutAnimation(ViewFlipperAnimations.NEXT_OUT); - flipper.showNext(); } + flipper.setDisplayedChild(position); if (page == 0) { cancelButton.setText(R.string.cancel); @@ -419,6 +411,11 @@ public class ReplyFragment extends DialogFragment { } else if (page == 2) { cancelButton.setText(R.string.close); } + + if (page == 1 && !gotInitialCaptcha) { + gotInitialCaptcha = true; + getCaptcha(); + } } /** @@ -608,7 +605,11 @@ public class ReplyFragment extends DialogFragment { submitButton.setEnabled(true); cancelButton.setEnabled(true); setClosable(true); - flipPage(1); + if (ChanPreferences.getPassEnabled()) { + flipPage(0); + } else { + flipPage(1); + } getCaptcha(); captchaInput.setText(""); } else if (response.isSuccessful) { diff --git a/Clover/app/src/main/res/values/strings.xml b/Clover/app/src/main/res/values/strings.xml index 8f5513db..3f2d2d6a 100644 --- a/Clover/app/src/main/res/values/strings.xml +++ b/Clover/app/src/main/res/values/strings.xml @@ -270,7 +270,6 @@ along with this program. If not, see . Connection error Using 4chan pass Off - Using 4chan pass %1$s images will be downloaded to %2$s From 53d52e65a287931dadad65c13875514d3d63d4e7 Mon Sep 17 00:00:00 2001 From: Floens Date: Sat, 7 Feb 2015 01:40:40 +0100 Subject: [PATCH 14/14] Release v1.2.9 --- CHANGES.txt | 4 ++++ Clover/app/build.gradle | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index eafb5425..fc98a0bc 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,7 @@ +New in 1.2.9 (2015-02-06) +- More captcha fixing, should be easier now. + + New in 1.2.8 (2015-02-06) - Fix captcha not working diff --git a/Clover/app/build.gradle b/Clover/app/build.gradle index abf6edb4..376d42d0 100644 --- a/Clover/app/build.gradle +++ b/Clover/app/build.gradle @@ -8,8 +8,8 @@ android { minSdkVersion 14 targetSdkVersion 21 - versionName "v1.2.8" - versionCode 47 + versionName "v1.2.9" + versionCode 48 } compileOptions {