mirror of https://github.com/ThmmyNoLife/mTHMMY
Browse Source
Change TopicActivity to MVVM arch using ViewModel, Add EditPost, Clean-up TopicActivity, Add post focus, Other changes and fixespull/44/head
oogee
6 years ago
committed by
Apostolof
24 changed files with 1829 additions and 876 deletions
File diff suppressed because it is too large
@ -0,0 +1,61 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.activities.topic.Posting; |
||||
|
import gr.thmmy.mthmmy.base.BaseApplication; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
public class DeleteTask extends AsyncTask<String, Void, Boolean> { |
||||
|
private DeleteTaskCallbacks listener; |
||||
|
|
||||
|
public DeleteTask(DeleteTaskCallbacks listener) { |
||||
|
this.listener = listener; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPreExecute() { |
||||
|
listener.onDeleteTaskStarted(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected Boolean doInBackground(String... args) { |
||||
|
Request delete = new Request.Builder() |
||||
|
.url(args[0]) |
||||
|
.header("User-Agent", |
||||
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
OkHttpClient client = BaseApplication.getInstance().getClient(); |
||||
|
client.newCall(delete).execute(); |
||||
|
Response response = client.newCall(delete).execute(); |
||||
|
//Response response = client.newCall(delete).execute();
|
||||
|
switch (Posting.replyStatus(response)) { |
||||
|
case SUCCESSFUL: |
||||
|
return true; |
||||
|
default: |
||||
|
Timber.e("Something went wrong. Request string: %s", delete.toString()); |
||||
|
return true; |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
Timber.e(e, "Delete failed."); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPostExecute(Boolean result) { |
||||
|
listener.onDeleteTaskFinished(result); |
||||
|
} |
||||
|
|
||||
|
public interface DeleteTaskCallbacks { |
||||
|
void onDeleteTaskStarted(); |
||||
|
void onDeleteTaskFinished(boolean result); |
||||
|
} |
||||
|
} |
@ -0,0 +1,77 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.base.BaseApplication; |
||||
|
import okhttp3.MultipartBody; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.RequestBody; |
||||
|
import okhttp3.Response; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; |
||||
|
|
||||
|
public class EditTask extends AsyncTask<String, Void, Boolean> { |
||||
|
private EditTaskCallbacks listener; |
||||
|
private int position; |
||||
|
|
||||
|
public EditTask(EditTaskCallbacks listener, int position) { |
||||
|
this.listener = listener; |
||||
|
this.position = position; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPreExecute() { |
||||
|
listener.onEditTaskStarted(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected Boolean doInBackground(String... strings) { |
||||
|
RequestBody postBody = new MultipartBody.Builder() |
||||
|
.setType(MultipartBody.FORM) |
||||
|
.addFormDataPart("message", strings[1]) |
||||
|
.addFormDataPart("num_replies", strings[2]) |
||||
|
.addFormDataPart("seqnum", strings[3]) |
||||
|
.addFormDataPart("sc", strings[4]) |
||||
|
.addFormDataPart("subject", strings[5]) |
||||
|
.addFormDataPart("topic", strings[6]) |
||||
|
.build(); |
||||
|
Request post = new Request.Builder() |
||||
|
.url(strings[0]) |
||||
|
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") |
||||
|
.post(postBody) |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
OkHttpClient client = BaseApplication.getInstance().getClient(); |
||||
|
client.newCall(post).execute(); |
||||
|
Response response = client.newCall(post).execute(); |
||||
|
switch (replyStatus(response)) { |
||||
|
case SUCCESSFUL: |
||||
|
return true; |
||||
|
case NEW_REPLY_WHILE_POSTING: |
||||
|
//TODO this...
|
||||
|
return true; |
||||
|
default: |
||||
|
Timber.e("Malformed post. Request string: %s", post.toString()); |
||||
|
return true; |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
Timber.e(e, "Edit failed."); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPostExecute(Boolean result) { |
||||
|
listener.onEditTaskFinished(result, position); |
||||
|
} |
||||
|
|
||||
|
public interface EditTaskCallbacks { |
||||
|
void onEditTaskStarted(); |
||||
|
void onEditTaskFinished(boolean result, int position); |
||||
|
} |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
public class PrepareForEditResult { |
||||
|
private final String postText, commitEditUrl, numReplies, seqnum, sc, topic; |
||||
|
private int position; |
||||
|
private boolean successful; |
||||
|
|
||||
|
public PrepareForEditResult(String postText, String commitEditUrl, String numReplies, String seqnum, |
||||
|
String sc, String topic, int position, boolean successful) { |
||||
|
this.postText = postText; |
||||
|
this.commitEditUrl = commitEditUrl; |
||||
|
this.numReplies = numReplies; |
||||
|
this.seqnum = seqnum; |
||||
|
this.sc = sc; |
||||
|
this.topic = topic; |
||||
|
this.position = position; |
||||
|
this.successful = successful; |
||||
|
} |
||||
|
|
||||
|
public String getPostText() { |
||||
|
return postText; |
||||
|
} |
||||
|
|
||||
|
public String getCommitEditUrl() { |
||||
|
return commitEditUrl; |
||||
|
} |
||||
|
|
||||
|
public String getNumReplies() { |
||||
|
return numReplies; |
||||
|
} |
||||
|
|
||||
|
public String getSeqnum() { |
||||
|
return seqnum; |
||||
|
} |
||||
|
|
||||
|
public String getSc() { |
||||
|
return sc; |
||||
|
} |
||||
|
|
||||
|
public String getTopic() { |
||||
|
return topic; |
||||
|
} |
||||
|
|
||||
|
public int getPosition() { |
||||
|
return position; |
||||
|
} |
||||
|
|
||||
|
public boolean isSuccessful() { |
||||
|
return successful; |
||||
|
} |
||||
|
} |
@ -0,0 +1,80 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
|
||||
|
import org.jsoup.Jsoup; |
||||
|
import org.jsoup.nodes.Document; |
||||
|
import org.jsoup.nodes.Element; |
||||
|
import org.jsoup.select.Selector; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditResult; |
||||
|
import gr.thmmy.mthmmy.base.BaseApplication; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
public class PrepareForEditTask extends AsyncTask<String, Void, PrepareForEditResult> { |
||||
|
private int position; |
||||
|
private String replyPageUrl; |
||||
|
private PrepareForEditCallbacks listener; |
||||
|
private OnPrepareEditFinished finishListener; |
||||
|
|
||||
|
public PrepareForEditTask(PrepareForEditCallbacks listener, OnPrepareEditFinished finishListener, int position, String replyPageUrl) { |
||||
|
this.listener = listener; |
||||
|
this.finishListener = finishListener; |
||||
|
this.position = position; |
||||
|
this.replyPageUrl = replyPageUrl; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPreExecute() { |
||||
|
listener.onPrepareEditStarted(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected PrepareForEditResult doInBackground(String... strings) { |
||||
|
Document document; |
||||
|
String url = strings[0]; |
||||
|
Request request = new Request.Builder() |
||||
|
.url(url + ";wap2") |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
String postText, commitEditURL, numReplies, seqnum, sc, topic; |
||||
|
OkHttpClient client = BaseApplication.getInstance().getClient(); |
||||
|
Response response = client.newCall(request).execute(); |
||||
|
document = Jsoup.parse(response.body().string()); |
||||
|
|
||||
|
Element message = document.select("textarea").first(); |
||||
|
postText = message.text(); |
||||
|
|
||||
|
commitEditURL = document.select("form").first().attr("action"); |
||||
|
numReplies = replyPageUrl.substring(replyPageUrl.indexOf("num_replies=") + 12); |
||||
|
seqnum = document.select("input[name=seqnum]").first().attr("value"); |
||||
|
sc = document.select("input[name=sc]").first().attr("value"); |
||||
|
topic = document.select("input[name=topic]").first().attr("value"); |
||||
|
|
||||
|
return new PrepareForEditResult(postText, commitEditURL, numReplies, seqnum, sc, topic, position, true); |
||||
|
} catch (IOException | Selector.SelectorParseException e) { |
||||
|
Timber.e(e, "Prepare failed."); |
||||
|
return new PrepareForEditResult(null, null, null, null, null, null, position, false); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPostExecute(PrepareForEditResult result) { |
||||
|
finishListener.onPrepareEditFinished(result, position); |
||||
|
} |
||||
|
|
||||
|
public interface PrepareForEditCallbacks { |
||||
|
void onPrepareEditStarted(); |
||||
|
void onPrepareEditCancelled(); |
||||
|
} |
||||
|
|
||||
|
public interface OnPrepareEditFinished { |
||||
|
void onPrepareEditFinished(PrepareForEditResult result, int position); |
||||
|
} |
||||
|
} |
@ -0,0 +1,91 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
|
||||
|
import org.jsoup.Jsoup; |
||||
|
import org.jsoup.nodes.Document; |
||||
|
import org.jsoup.select.Selector; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.base.BaseApplication; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
public class PrepareForReply extends AsyncTask<Integer, Void, PrepareForReplyResult> { |
||||
|
private PrepareForReplyCallbacks listener; |
||||
|
private OnPrepareForReplyFinished finishListener; |
||||
|
private String replyPageUrl; |
||||
|
|
||||
|
public PrepareForReply(PrepareForReplyCallbacks listener, OnPrepareForReplyFinished finishListener, |
||||
|
String replyPageUrl) { |
||||
|
this.listener = listener; |
||||
|
this.finishListener = finishListener; |
||||
|
this.replyPageUrl = replyPageUrl; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPreExecute() { |
||||
|
listener.onPrepareForReplyStarted(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected PrepareForReplyResult doInBackground(Integer... postIndices) { |
||||
|
String numReplies = null; |
||||
|
String seqnum = null; |
||||
|
String sc = null; |
||||
|
String topic = null; |
||||
|
StringBuilder buildedQuotes = new StringBuilder(""); |
||||
|
|
||||
|
Document document; |
||||
|
Request request = new Request.Builder() |
||||
|
.url(replyPageUrl + ";wap2") |
||||
|
.build(); |
||||
|
|
||||
|
OkHttpClient client = BaseApplication.getInstance().getClient(); |
||||
|
try { |
||||
|
Response response = client.newCall(request).execute(); |
||||
|
document = Jsoup.parse(response.body().string()); |
||||
|
|
||||
|
numReplies = replyPageUrl.substring(replyPageUrl.indexOf("num_replies=") + 12); |
||||
|
seqnum = document.select("input[name=seqnum]").first().attr("value"); |
||||
|
sc = document.select("input[name=sc]").first().attr("value"); |
||||
|
topic = document.select("input[name=topic]").first().attr("value"); |
||||
|
} catch (IOException | Selector.SelectorParseException e) { |
||||
|
Timber.e(e, "Prepare failed."); |
||||
|
} |
||||
|
|
||||
|
for (Integer postIndex : postIndices) { |
||||
|
request = new Request.Builder() |
||||
|
.url("https://www.thmmy.gr/smf/index.php?action=quotefast;quote=" + |
||||
|
postIndex + ";" + "sesc=" + sc + ";xml") |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
Response response = client.newCall(request).execute(); |
||||
|
String body = response.body().string(); |
||||
|
buildedQuotes.append(body.substring(body.indexOf("<quote>") + 7, body.indexOf("</quote>"))); |
||||
|
buildedQuotes.append("\n\n"); |
||||
|
} catch (IOException | Selector.SelectorParseException e) { |
||||
|
Timber.e(e, "Quote building failed."); |
||||
|
} |
||||
|
} |
||||
|
return new PrepareForReplyResult(numReplies, seqnum, sc, topic, buildedQuotes.toString()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPostExecute(PrepareForReplyResult result) { |
||||
|
finishListener.onPrepareForReplyFinished(result); |
||||
|
} |
||||
|
|
||||
|
public interface PrepareForReplyCallbacks { |
||||
|
void onPrepareForReplyStarted(); |
||||
|
void onPrepareForReplyCancelled(); |
||||
|
} |
||||
|
|
||||
|
public interface OnPrepareForReplyFinished { |
||||
|
void onPrepareForReplyFinished(PrepareForReplyResult result); |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
public class PrepareForReplyResult { |
||||
|
private final String numReplies, seqnum, sc, topic, buildedQuotes; |
||||
|
|
||||
|
|
||||
|
public PrepareForReplyResult(String numReplies, String seqnum, String sc, String topic, String buildedQuotes) { |
||||
|
this.numReplies = numReplies; |
||||
|
this.seqnum = seqnum; |
||||
|
this.sc = sc; |
||||
|
this.topic = topic; |
||||
|
this.buildedQuotes = buildedQuotes; |
||||
|
} |
||||
|
|
||||
|
public String getNumReplies() { |
||||
|
return numReplies; |
||||
|
} |
||||
|
|
||||
|
public String getSeqnum() { |
||||
|
return seqnum; |
||||
|
} |
||||
|
|
||||
|
public String getSc() { |
||||
|
return sc; |
||||
|
} |
||||
|
|
||||
|
public String getTopic() { |
||||
|
return topic; |
||||
|
} |
||||
|
|
||||
|
public String getBuildedQuotes() { |
||||
|
return buildedQuotes; |
||||
|
} |
||||
|
} |
@ -0,0 +1,80 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.base.BaseApplication; |
||||
|
import okhttp3.MultipartBody; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.RequestBody; |
||||
|
import okhttp3.Response; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; |
||||
|
|
||||
|
public class ReplyTask extends AsyncTask<String, Void, Boolean> { |
||||
|
private ReplyTaskCallbacks listener; |
||||
|
private boolean includeAppSignature; |
||||
|
|
||||
|
public ReplyTask(ReplyTaskCallbacks listener, boolean includeAppSignature) { |
||||
|
this.listener = listener; |
||||
|
this.includeAppSignature = includeAppSignature; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPreExecute() { |
||||
|
listener.onReplyTaskStarted(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected Boolean doInBackground(String... args) { |
||||
|
final String sentFrommTHMMY = includeAppSignature |
||||
|
? "\n[right][size=7pt][i]sent from [url=https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy]mTHMMY [/url][/i][/size][/right]" |
||||
|
: ""; |
||||
|
RequestBody postBody = new MultipartBody.Builder() |
||||
|
.setType(MultipartBody.FORM) |
||||
|
.addFormDataPart("message", args[1] + sentFrommTHMMY) |
||||
|
.addFormDataPart("num_replies", args[2]) |
||||
|
.addFormDataPart("seqnum", args[3]) |
||||
|
.addFormDataPart("sc", args[4]) |
||||
|
.addFormDataPart("subject", args[0]) |
||||
|
.addFormDataPart("topic", args[5]) |
||||
|
.build(); |
||||
|
Request post = new Request.Builder() |
||||
|
.url("https://www.thmmy.gr/smf/index.php?action=post2") |
||||
|
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") |
||||
|
.post(postBody) |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
OkHttpClient client = BaseApplication.getInstance().getClient(); |
||||
|
client.newCall(post).execute(); |
||||
|
Response response = client.newCall(post).execute(); |
||||
|
switch (replyStatus(response)) { |
||||
|
case SUCCESSFUL: |
||||
|
return true; |
||||
|
case NEW_REPLY_WHILE_POSTING: |
||||
|
//TODO this...
|
||||
|
return true; |
||||
|
default: |
||||
|
Timber.e("Malformed post. Request string: %s", post.toString()); |
||||
|
return true; |
||||
|
} |
||||
|
} catch (IOException e) { |
||||
|
Timber.e(e, "Post failed."); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPostExecute(Boolean result) { |
||||
|
listener.onReplyTaskFinished(result); |
||||
|
} |
||||
|
|
||||
|
public interface ReplyTaskCallbacks { |
||||
|
void onReplyTaskStarted(); |
||||
|
void onReplyTaskFinished(boolean result); |
||||
|
} |
||||
|
} |
@ -0,0 +1,172 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
import android.util.SparseArray; |
||||
|
|
||||
|
import org.jsoup.Jsoup; |
||||
|
import org.jsoup.nodes.Document; |
||||
|
import org.jsoup.nodes.Element; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
import java.util.ArrayList; |
||||
|
import java.util.Objects; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.activities.topic.TopicParser; |
||||
|
import gr.thmmy.mthmmy.base.BaseApplication; |
||||
|
import gr.thmmy.mthmmy.model.Post; |
||||
|
import gr.thmmy.mthmmy.model.ThmmyPage; |
||||
|
import gr.thmmy.mthmmy.utils.parsing.ParseException; |
||||
|
import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
/** |
||||
|
* An {@link AsyncTask} that handles asynchronous fetching of this topic page and parsing of its |
||||
|
* data. |
||||
|
* <p>TopicTask's {@link AsyncTask#execute execute} method needs a topic's url as String |
||||
|
* parameter.</p> |
||||
|
*/ |
||||
|
public class TopicTask extends AsyncTask<String, Void, TopicTaskResult> { |
||||
|
private TopicTaskObserver topicTaskObserver; |
||||
|
private OnTopicTaskCompleted finishListener; |
||||
|
|
||||
|
public TopicTask(TopicTaskObserver topicTaskObserver, OnTopicTaskCompleted finishListener) { |
||||
|
this.topicTaskObserver = topicTaskObserver; |
||||
|
this.finishListener = finishListener; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPreExecute() { |
||||
|
topicTaskObserver.onTopicTaskStarted(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected TopicTaskResult doInBackground(String... strings) { |
||||
|
String topicTitle = null; |
||||
|
String topicTreeAndMods = ""; |
||||
|
String topicViewers = ""; |
||||
|
ArrayList<Post> newPostsList = null; |
||||
|
int loadedPageTopicId = -1; |
||||
|
int focusedPostIndex = 0; |
||||
|
SparseArray<String> pagesUrls = new SparseArray<>(); |
||||
|
int currentPageIndex = 1; |
||||
|
int pageCount = 1; |
||||
|
String baseUrl = ""; |
||||
|
String lastPageLoadAttemptedUrl = ""; |
||||
|
|
||||
|
Document topic = null; |
||||
|
String newPageUrl = strings[0]; |
||||
|
|
||||
|
//Finds the index of message focus if present
|
||||
|
int postFocus = 0; |
||||
|
{ |
||||
|
if (newPageUrl.contains("msg")) { |
||||
|
String tmp = newPageUrl.substring(newPageUrl.indexOf("msg") + 3); |
||||
|
if (tmp.contains(";")) |
||||
|
postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf(";"))); |
||||
|
else if (tmp.contains("#")) |
||||
|
postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf("#"))); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
lastPageLoadAttemptedUrl = newPageUrl; |
||||
|
if (strings[0].substring(0, strings[0].lastIndexOf(".")).contains("topic=")) |
||||
|
baseUrl = strings[0].substring(0, strings[0].lastIndexOf(".")); //New topic's base url
|
||||
|
String replyPageUrl = null; |
||||
|
Request request = new Request.Builder() |
||||
|
.url(newPageUrl) |
||||
|
.build(); |
||||
|
ResultCode resultCode; |
||||
|
try { |
||||
|
Response response = BaseApplication.getInstance().getClient().newCall(request).execute(); |
||||
|
topic = Jsoup.parse(response.body().string()); |
||||
|
|
||||
|
ParseHelpers.Language language = ParseHelpers.Language.getLanguage(topic); |
||||
|
|
||||
|
//Finds topic's tree, mods and users viewing
|
||||
|
topicTreeAndMods = topic.select("div.nav").first().html(); |
||||
|
topicViewers = TopicParser.parseUsersViewingThisTopic(topic, language); |
||||
|
|
||||
|
//Finds reply page url
|
||||
|
Element replyButton = topic.select("a:has(img[alt=Reply])").first(); |
||||
|
if (replyButton == null) |
||||
|
replyButton = topic.select("a:has(img[alt=Απάντηση])").first(); |
||||
|
if (replyButton != null) replyPageUrl = replyButton.attr("href"); |
||||
|
|
||||
|
//Finds topic title if missing
|
||||
|
topicTitle = topic.select("td[id=top_subject]").first().text(); |
||||
|
if (topicTitle.contains("Topic:")) { |
||||
|
topicTitle = topicTitle.substring(topicTitle.indexOf("Topic:") + 7 |
||||
|
, topicTitle.indexOf("(Read") - 2); |
||||
|
} else { |
||||
|
topicTitle = topicTitle.substring(topicTitle.indexOf("Θέμα:") + 6 |
||||
|
, topicTitle.indexOf("(Αναγνώστηκε") - 2); |
||||
|
Timber.d("Parsed title: %s", topicTitle); |
||||
|
} |
||||
|
|
||||
|
//Finds current page's index
|
||||
|
currentPageIndex = TopicParser.parseCurrentPageIndex(topic, language); |
||||
|
|
||||
|
//Finds number of pages
|
||||
|
pageCount = TopicParser.parseTopicNumberOfPages(topic, currentPageIndex, language); |
||||
|
|
||||
|
for (int i = 0; i < pageCount; i++) { |
||||
|
//Generate each page's url from topic's base url +".15*numberOfPage"
|
||||
|
pagesUrls.put(i, baseUrl + "." + String.valueOf(i * 15)); |
||||
|
} |
||||
|
|
||||
|
newPostsList = TopicParser.parseTopic(topic, language); |
||||
|
|
||||
|
loadedPageTopicId = Integer.parseInt(ThmmyPage.getTopicId(lastPageLoadAttemptedUrl)); |
||||
|
|
||||
|
//Finds the position of the focused message if present
|
||||
|
for (int i = 0; i < newPostsList.size(); ++i) { |
||||
|
if (newPostsList.get(i).getPostIndex() == postFocus) { |
||||
|
focusedPostIndex = i; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
resultCode = ResultCode.SUCCESS; |
||||
|
} catch (IOException e) { |
||||
|
Timber.i(e, "IO Exception"); |
||||
|
resultCode = ResultCode.NETWORK_ERROR; |
||||
|
} catch (Exception e) { |
||||
|
if (isUnauthorized(topic)) { |
||||
|
resultCode = ResultCode.UNAUTHORIZED; |
||||
|
} else { |
||||
|
Timber.e(e, "Parsing Error"); |
||||
|
resultCode = ResultCode.PARSING_ERROR; |
||||
|
} |
||||
|
} |
||||
|
return new TopicTaskResult(resultCode, baseUrl, topicTitle, replyPageUrl, newPostsList, |
||||
|
loadedPageTopicId, currentPageIndex, pageCount, focusedPostIndex, topicTreeAndMods, |
||||
|
topicViewers, lastPageLoadAttemptedUrl, pagesUrls); |
||||
|
} |
||||
|
|
||||
|
private boolean isUnauthorized(Document document) { |
||||
|
return document != null && document.select("body:contains(The topic or board you" + |
||||
|
" are looking for appears to be either missing or off limits to you.)," + |
||||
|
"body:contains(Το θέμα ή πίνακας που ψάχνετε ή δεν υπάρχει ή δεν " + |
||||
|
"είναι προσβάσιμο από εσάς.)").size() > 0; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onPostExecute(TopicTaskResult topicTaskResult) { |
||||
|
finishListener.onTopicTaskCompleted(topicTaskResult); |
||||
|
} |
||||
|
|
||||
|
public enum ResultCode { |
||||
|
SUCCESS, NETWORK_ERROR, PARSING_ERROR, UNAUTHORIZED |
||||
|
} |
||||
|
|
||||
|
public interface TopicTaskObserver { |
||||
|
void onTopicTaskStarted(); |
||||
|
|
||||
|
void onTopicTaskCancelled(); |
||||
|
} |
||||
|
|
||||
|
public interface OnTopicTaskCompleted { |
||||
|
void onTopicTaskCompleted(TopicTaskResult result); |
||||
|
} |
||||
|
} |
@ -0,0 +1,125 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.topic.tasks; |
||||
|
|
||||
|
import android.util.SparseArray; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; |
||||
|
import gr.thmmy.mthmmy.model.Post; |
||||
|
|
||||
|
public class TopicTaskResult { |
||||
|
private final TopicTask.ResultCode resultCode; |
||||
|
/** |
||||
|
* Holds this topic's base url. For example a topic with url similar to |
||||
|
* "https://www.thmmy.gr/smf/index.php?topic=1.15;topicseen" or |
||||
|
* "https://www.thmmy.gr/smf/index.php?topic=1.msg1#msg1" |
||||
|
* has the base url "https://www.thmmy.gr/smf/index.php?topic=1" |
||||
|
*/ |
||||
|
private final String baseUrl; |
||||
|
/** |
||||
|
* Holds this topic's title. At first this gets the value of the topic title that came with |
||||
|
* bundle and is rendered in the toolbar while parsing this topic. Later, if a different topic |
||||
|
* title is parsed from the html source, it gets updated. |
||||
|
*/ |
||||
|
private final String topicTitle; |
||||
|
/** |
||||
|
* This topic's reply url |
||||
|
*/ |
||||
|
private final String replyPageUrl; |
||||
|
private final ArrayList<Post> newPostsList; |
||||
|
/** |
||||
|
* The topicId of the loaded page |
||||
|
*/ |
||||
|
private final int loadedPageTopicId; |
||||
|
/** |
||||
|
* Holds current page's index (starting from 1, not 0) |
||||
|
*/ |
||||
|
private final int currentPageIndex; |
||||
|
/** |
||||
|
* Holds the requested topic's number of pages |
||||
|
*/ |
||||
|
private final int pageCount; |
||||
|
/** |
||||
|
* The index of the post that has focus |
||||
|
*/ |
||||
|
private final int focusedPostIndex; |
||||
|
//Topic's info related
|
||||
|
private final String topicTreeAndMods; |
||||
|
private final String topicViewers; |
||||
|
/** |
||||
|
* The url of the last page that was attempted to be loaded |
||||
|
*/ |
||||
|
private final String lastPageLoadAttemptedUrl; |
||||
|
private final SparseArray<String> pagesUrls; |
||||
|
|
||||
|
public TopicTaskResult(TopicTask.ResultCode resultCode, String baseUrl, String topicTitle, |
||||
|
String replyPageUrl, ArrayList<Post> newPostsList, int loadedPageTopicId, |
||||
|
int currentPageIndex, int pageCount, int focusedPostIndex, String topicTreeAndMods, |
||||
|
String topicViewers, String lastPageLoadAttemptedUrl, SparseArray<String> pagesUrls) { |
||||
|
this.resultCode = resultCode; |
||||
|
this.baseUrl = baseUrl; |
||||
|
this.topicTitle = topicTitle; |
||||
|
this.replyPageUrl = replyPageUrl; |
||||
|
this.newPostsList = newPostsList; |
||||
|
this.loadedPageTopicId = loadedPageTopicId; |
||||
|
this.currentPageIndex = currentPageIndex; |
||||
|
this.pageCount = pageCount; |
||||
|
this.focusedPostIndex = focusedPostIndex; |
||||
|
this.topicTreeAndMods = topicTreeAndMods; |
||||
|
this.topicViewers = topicViewers; |
||||
|
this.lastPageLoadAttemptedUrl = lastPageLoadAttemptedUrl; |
||||
|
this.pagesUrls = pagesUrls; |
||||
|
} |
||||
|
|
||||
|
public TopicTask.ResultCode getResultCode() { |
||||
|
return resultCode; |
||||
|
} |
||||
|
|
||||
|
public String getBaseUrl() { |
||||
|
return baseUrl; |
||||
|
} |
||||
|
|
||||
|
public String getTopicTitle() { |
||||
|
return topicTitle; |
||||
|
} |
||||
|
|
||||
|
public String getReplyPageUrl() { |
||||
|
return replyPageUrl; |
||||
|
} |
||||
|
|
||||
|
public ArrayList<Post> getNewPostsList() { |
||||
|
return newPostsList; |
||||
|
} |
||||
|
|
||||
|
public int getLoadedPageTopicId() { |
||||
|
return loadedPageTopicId; |
||||
|
} |
||||
|
|
||||
|
public int getCurrentPageIndex() { |
||||
|
return currentPageIndex; |
||||
|
} |
||||
|
|
||||
|
public int getPageCount() { |
||||
|
return pageCount; |
||||
|
} |
||||
|
|
||||
|
public int getFocusedPostIndex() { |
||||
|
return focusedPostIndex; |
||||
|
} |
||||
|
|
||||
|
public String getTopicTreeAndMods() { |
||||
|
return topicTreeAndMods; |
||||
|
} |
||||
|
|
||||
|
public String getTopicViewers() { |
||||
|
return topicViewers; |
||||
|
} |
||||
|
|
||||
|
public String getLastPageLoadAttemptedUrl() { |
||||
|
return lastPageLoadAttemptedUrl; |
||||
|
} |
||||
|
|
||||
|
public SparseArray<String> getPagesUrls() { |
||||
|
return pagesUrls; |
||||
|
} |
||||
|
} |
@ -0,0 +1,76 @@ |
|||||
|
package gr.thmmy.mthmmy.utils; |
||||
|
|
||||
|
import android.app.Activity; |
||||
|
import android.content.Intent; |
||||
|
import android.net.Uri; |
||||
|
import android.os.Build; |
||||
|
import android.os.Bundle; |
||||
|
import android.text.Html; |
||||
|
import android.text.SpannableStringBuilder; |
||||
|
import android.text.style.ClickableSpan; |
||||
|
import android.text.style.URLSpan; |
||||
|
import android.view.View; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.activities.board.BoardActivity; |
||||
|
import gr.thmmy.mthmmy.activities.profile.ProfileActivity; |
||||
|
import gr.thmmy.mthmmy.model.ThmmyPage; |
||||
|
|
||||
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; |
||||
|
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE; |
||||
|
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL; |
||||
|
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL; |
||||
|
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL; |
||||
|
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME; |
||||
|
|
||||
|
public class HTMLUtils { |
||||
|
private HTMLUtils() {} |
||||
|
|
||||
|
public static SpannableStringBuilder getSpannableFromHtml(Activity activity, String html) { |
||||
|
CharSequence sequence; |
||||
|
if (Build.VERSION.SDK_INT >= 24) { |
||||
|
sequence = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY); |
||||
|
} else { |
||||
|
//noinspection deprecation
|
||||
|
sequence = Html.fromHtml(html); |
||||
|
} |
||||
|
SpannableStringBuilder strBuilder = new SpannableStringBuilder(sequence); |
||||
|
URLSpan[] urls = strBuilder.getSpans(0, sequence.length(), URLSpan.class); |
||||
|
for (URLSpan span : urls) { |
||||
|
makeLinkClickable(activity, strBuilder, span); |
||||
|
} |
||||
|
return strBuilder; |
||||
|
} |
||||
|
|
||||
|
private static void makeLinkClickable(Activity activity, SpannableStringBuilder strBuilder, final URLSpan span) { |
||||
|
int start = strBuilder.getSpanStart(span); |
||||
|
int end = strBuilder.getSpanEnd(span); |
||||
|
int flags = strBuilder.getSpanFlags(span); |
||||
|
ClickableSpan clickable = new ClickableSpan() { |
||||
|
@Override |
||||
|
public void onClick(View view) { |
||||
|
ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(span.getURL())); |
||||
|
if (target.is(ThmmyPage.PageCategory.BOARD)) { |
||||
|
Intent intent = new Intent(activity.getApplicationContext(), BoardActivity.class); |
||||
|
Bundle extras = new Bundle(); |
||||
|
extras.putString(BUNDLE_BOARD_URL, span.getURL()); |
||||
|
extras.putString(BUNDLE_BOARD_TITLE, ""); |
||||
|
intent.putExtras(extras); |
||||
|
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); |
||||
|
activity.getApplicationContext().startActivity(intent); |
||||
|
} else if (target.is(ThmmyPage.PageCategory.PROFILE)) { |
||||
|
Intent intent = new Intent(activity.getApplicationContext(), ProfileActivity.class); |
||||
|
Bundle extras = new Bundle(); |
||||
|
extras.putString(BUNDLE_PROFILE_URL, span.getURL()); |
||||
|
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); |
||||
|
extras.putString(BUNDLE_PROFILE_USERNAME, ""); |
||||
|
intent.putExtras(extras); |
||||
|
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); |
||||
|
activity.getApplicationContext().startActivity(intent); |
||||
|
} else if (target.is(ThmmyPage.PageCategory.INDEX)) |
||||
|
activity.finish(); |
||||
|
} |
||||
|
}; |
||||
|
strBuilder.setSpan(clickable, start, end, flags); |
||||
|
strBuilder.removeSpan(span); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
package gr.thmmy.mthmmy.viewmodel; |
||||
|
|
||||
|
import android.arch.lifecycle.LiveData; |
||||
|
import android.arch.lifecycle.MutableLiveData; |
||||
|
import android.arch.lifecycle.ViewModel; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.model.Bookmark; |
||||
|
|
||||
|
public class BaseViewModel extends ViewModel { |
||||
|
protected MutableLiveData<Bookmark> currentPageBookmark; |
||||
|
|
||||
|
public LiveData<Bookmark> getCurrentPageBookmark() { |
||||
|
if (currentPageBookmark == null) { |
||||
|
currentPageBookmark = new MutableLiveData<>(); |
||||
|
} |
||||
|
return currentPageBookmark; |
||||
|
} |
||||
|
} |
@ -0,0 +1,316 @@ |
|||||
|
package gr.thmmy.mthmmy.viewmodel; |
||||
|
|
||||
|
import android.arch.lifecycle.MutableLiveData; |
||||
|
import android.content.Context; |
||||
|
import android.content.SharedPreferences; |
||||
|
import android.os.AsyncTask; |
||||
|
import android.preference.PreferenceManager; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.activities.settings.SettingsActivity; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.DeleteTask; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.EditTask; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditResult; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForEditTask; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReply; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.PrepareForReplyResult; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.ReplyTask; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.TopicTask; |
||||
|
import gr.thmmy.mthmmy.activities.topic.tasks.TopicTaskResult; |
||||
|
import gr.thmmy.mthmmy.base.BaseActivity; |
||||
|
import gr.thmmy.mthmmy.model.Post; |
||||
|
import gr.thmmy.mthmmy.session.SessionManager; |
||||
|
|
||||
|
public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTaskCompleted, |
||||
|
PrepareForReply.OnPrepareForReplyFinished, PrepareForEditTask.OnPrepareEditFinished { |
||||
|
/** |
||||
|
* topic state |
||||
|
*/ |
||||
|
private boolean editingPost = false; |
||||
|
private boolean writingReply = false; |
||||
|
/** |
||||
|
* A list of {@link Post#getPostIndex()} for building quotes for replying |
||||
|
*/ |
||||
|
private ArrayList<Integer> toQuoteList = new ArrayList<>(); |
||||
|
/** |
||||
|
* caches the expand/collapse state of the user extra info in the current page for the recyclerview |
||||
|
*/ |
||||
|
private ArrayList<Boolean> isUserExtraInfoVisibile = new ArrayList<>(); |
||||
|
/** |
||||
|
* holds the adapter position of the post being edited |
||||
|
*/ |
||||
|
private int postBeingEditedPosition; |
||||
|
|
||||
|
private TopicTask currentTopicTask; |
||||
|
private PrepareForEditTask currentPrepareForEditTask; |
||||
|
private PrepareForReply currentPrepareForReplyTask; |
||||
|
|
||||
|
//callbacks for topic activity
|
||||
|
private TopicTask.TopicTaskObserver topicTaskObserver; |
||||
|
private DeleteTask.DeleteTaskCallbacks deleteTaskCallbacks; |
||||
|
private ReplyTask.ReplyTaskCallbacks replyFinishListener; |
||||
|
private PrepareForEditTask.PrepareForEditCallbacks prepareForEditCallbacks; |
||||
|
private EditTask.EditTaskCallbacks editTaskCallbacks; |
||||
|
private PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks; |
||||
|
|
||||
|
private MutableLiveData<TopicTaskResult> topicTaskResult = new MutableLiveData<>(); |
||||
|
private MutableLiveData<PrepareForReplyResult> prepareForReplyResult = new MutableLiveData<>(); |
||||
|
private MutableLiveData<PrepareForEditResult> prepareForEditResult = new MutableLiveData<>(); |
||||
|
|
||||
|
private String firstTopicUrl; |
||||
|
|
||||
|
public void initialLoad(String pageUrl) { |
||||
|
firstTopicUrl = pageUrl; |
||||
|
currentTopicTask = new TopicTask(topicTaskObserver, this); |
||||
|
currentTopicTask.execute(pageUrl); |
||||
|
} |
||||
|
|
||||
|
public void loadUrl(String pageUrl) { |
||||
|
stopLoading(); |
||||
|
currentTopicTask = new TopicTask(topicTaskObserver, this); |
||||
|
currentTopicTask.execute(pageUrl); |
||||
|
} |
||||
|
|
||||
|
public void reloadPage() { |
||||
|
if (topicTaskResult.getValue() == null) |
||||
|
throw new NullPointerException("No topic task has finished yet!"); |
||||
|
loadUrl(topicTaskResult.getValue().getLastPageLoadAttemptedUrl()); |
||||
|
} |
||||
|
|
||||
|
public void changePage(int pageRequested) { |
||||
|
if (topicTaskResult.getValue() == null) |
||||
|
throw new NullPointerException("No page has been loaded yet!"); |
||||
|
if (pageRequested != topicTaskResult.getValue().getCurrentPageIndex() - 1) |
||||
|
loadUrl(topicTaskResult.getValue().getPagesUrls().get(pageRequested)); |
||||
|
} |
||||
|
|
||||
|
public void prepareForReply() { |
||||
|
if (topicTaskResult.getValue() == null) |
||||
|
throw new NullPointerException("Topic task has not finished yet!"); |
||||
|
stopLoading(); |
||||
|
changePage(topicTaskResult.getValue().getPageCount() - 1); |
||||
|
currentPrepareForReplyTask = new PrepareForReply(prepareForReplyCallbacks, this, |
||||
|
topicTaskResult.getValue().getReplyPageUrl()); |
||||
|
currentPrepareForReplyTask.execute(toQuoteList.toArray(new Integer[0])); |
||||
|
} |
||||
|
|
||||
|
public void postReply(Context context, String subject, String reply) { |
||||
|
if (prepareForReplyResult.getValue() == null) { |
||||
|
throw new NullPointerException("Reply preparation was not found!"); |
||||
|
} |
||||
|
PrepareForReplyResult replyForm = prepareForReplyResult.getValue(); |
||||
|
boolean includeAppSignature = true; |
||||
|
SessionManager sessionManager = BaseActivity.getSessionManager(); |
||||
|
if (sessionManager.isLoggedIn()) { |
||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); |
||||
|
includeAppSignature = prefs.getBoolean(SettingsActivity.POSTING_APP_SIGNATURE_ENABLE_KEY, true); |
||||
|
} |
||||
|
toQuoteList.clear(); |
||||
|
new ReplyTask(replyFinishListener, includeAppSignature).execute(subject, reply, |
||||
|
replyForm.getNumReplies(), replyForm.getSeqnum(), replyForm.getSc(), replyForm.getTopic()); |
||||
|
} |
||||
|
|
||||
|
public void deletePost(String postDeleteUrl) { |
||||
|
new DeleteTask(deleteTaskCallbacks).execute(postDeleteUrl); |
||||
|
} |
||||
|
|
||||
|
public void prepareForEdit(int position, String postEditURL) { |
||||
|
if (topicTaskResult.getValue() == null) |
||||
|
throw new NullPointerException("Topic task has not finished yet!"); |
||||
|
stopLoading(); |
||||
|
currentPrepareForEditTask = new PrepareForEditTask(prepareForEditCallbacks, this, position, |
||||
|
topicTaskResult.getValue().getReplyPageUrl()); |
||||
|
currentPrepareForEditTask.execute(postEditURL); |
||||
|
} |
||||
|
|
||||
|
public void editPost(int position, String subject, String message) { |
||||
|
if (prepareForEditResult.getValue() == null) |
||||
|
throw new NullPointerException("Edit preparation was not found!"); |
||||
|
PrepareForEditResult editResult = prepareForEditResult.getValue(); |
||||
|
new EditTask(editTaskCallbacks, position).execute(editResult.getCommitEditUrl(), message, |
||||
|
editResult.getNumReplies(), editResult.getSeqnum(), editResult.getSc(), subject, editResult.getTopic()); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* cancel tasks that change the ui |
||||
|
* topic, prepare for edit, prepare for reply tasks need to cancel all other ui changing tasks |
||||
|
* before starting |
||||
|
*/ |
||||
|
public void stopLoading() { |
||||
|
if (currentTopicTask != null && currentTopicTask.getStatus() == AsyncTask.Status.RUNNING) { |
||||
|
currentTopicTask.cancel(true); |
||||
|
topicTaskObserver.onTopicTaskCancelled(); |
||||
|
} |
||||
|
if (currentPrepareForEditTask != null && currentPrepareForEditTask.getStatus() == AsyncTask.Status.RUNNING) { |
||||
|
currentPrepareForEditTask.cancel(true); |
||||
|
prepareForEditCallbacks.onPrepareEditCancelled(); |
||||
|
} |
||||
|
if (currentPrepareForReplyTask != null && currentPrepareForReplyTask.getStatus() == AsyncTask.Status.RUNNING) { |
||||
|
currentPrepareForReplyTask.cancel(true); |
||||
|
prepareForReplyCallbacks.onPrepareForReplyCancelled(); |
||||
|
} |
||||
|
// no need to cancel reply, edit and delete task, user should not have to wait for the ui
|
||||
|
// after he is done posting, editing or deleting
|
||||
|
} |
||||
|
|
||||
|
// callbacks for viewmodel
|
||||
|
@Override |
||||
|
public void onTopicTaskCompleted(TopicTaskResult result) { |
||||
|
topicTaskResult.setValue(result); |
||||
|
if (result.getResultCode() == TopicTask.ResultCode.SUCCESS) { |
||||
|
isUserExtraInfoVisibile.clear(); |
||||
|
for (int i = 0; i < result.getNewPostsList().size(); i++) { |
||||
|
isUserExtraInfoVisibile.add(false); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onPrepareForReplyFinished(PrepareForReplyResult result) { |
||||
|
writingReply = true; |
||||
|
prepareForReplyResult.setValue(result); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onPrepareEditFinished(PrepareForEditResult result, int position) { |
||||
|
editingPost = true; |
||||
|
postBeingEditedPosition = position; |
||||
|
prepareForEditResult.setValue(result); |
||||
|
} |
||||
|
|
||||
|
// <-------------Just getters, setters and helper methods below here---------------->
|
||||
|
|
||||
|
public boolean isUserExtraInfoVisible(int position) { |
||||
|
return isUserExtraInfoVisibile.get(position); |
||||
|
} |
||||
|
|
||||
|
public void hideUserInfo(int position) { |
||||
|
isUserExtraInfoVisibile.set(position, false); |
||||
|
} |
||||
|
|
||||
|
public void toggleUserInfo(int position) { |
||||
|
isUserExtraInfoVisibile.set(position, !isUserExtraInfoVisibile.get(position)); |
||||
|
} |
||||
|
|
||||
|
public ArrayList<Integer> getToQuoteList() { |
||||
|
return toQuoteList; |
||||
|
} |
||||
|
|
||||
|
public void postIndexToggle(Integer postIndex) { |
||||
|
if (toQuoteList.contains(postIndex)) |
||||
|
toQuoteList.remove(postIndex); |
||||
|
else |
||||
|
toQuoteList.add(postIndex); |
||||
|
} |
||||
|
|
||||
|
public void setTopicTaskObserver(TopicTask.TopicTaskObserver topicTaskObserver) { |
||||
|
this.topicTaskObserver = topicTaskObserver; |
||||
|
} |
||||
|
|
||||
|
public void setDeleteTaskCallbacks(DeleteTask.DeleteTaskCallbacks deleteTaskCallbacks) { |
||||
|
this.deleteTaskCallbacks = deleteTaskCallbacks; |
||||
|
} |
||||
|
|
||||
|
public void setReplyFinishListener(ReplyTask.ReplyTaskCallbacks replyFinishListener) { |
||||
|
this.replyFinishListener = replyFinishListener; |
||||
|
} |
||||
|
|
||||
|
public void setPrepareForEditCallbacks(PrepareForEditTask.PrepareForEditCallbacks prepareForEditCallbacks) { |
||||
|
this.prepareForEditCallbacks = prepareForEditCallbacks; |
||||
|
} |
||||
|
|
||||
|
public void setEditTaskCallbacks(EditTask.EditTaskCallbacks editTaskCallbacks) { |
||||
|
this.editTaskCallbacks = editTaskCallbacks; |
||||
|
} |
||||
|
|
||||
|
public void setPrepareForReplyCallbacks(PrepareForReply.PrepareForReplyCallbacks prepareForReplyCallbacks) { |
||||
|
this.prepareForReplyCallbacks = prepareForReplyCallbacks; |
||||
|
} |
||||
|
|
||||
|
public MutableLiveData<TopicTaskResult> getTopicTaskResult() { |
||||
|
return topicTaskResult; |
||||
|
} |
||||
|
|
||||
|
public MutableLiveData<PrepareForReplyResult> getPrepareForReplyResult() { |
||||
|
return prepareForReplyResult; |
||||
|
} |
||||
|
|
||||
|
public MutableLiveData<PrepareForEditResult> getPrepareForEditResult() { |
||||
|
return prepareForEditResult; |
||||
|
} |
||||
|
|
||||
|
public void setEditingPost(boolean editingPost) { |
||||
|
this.editingPost = editingPost; |
||||
|
} |
||||
|
|
||||
|
public boolean isEditingPost() { |
||||
|
return editingPost; |
||||
|
} |
||||
|
|
||||
|
public int getPostBeingEditedPosition() { |
||||
|
return postBeingEditedPosition; |
||||
|
} |
||||
|
|
||||
|
public boolean canReply() { |
||||
|
return topicTaskResult.getValue() != null && topicTaskResult.getValue().getReplyPageUrl() != null; |
||||
|
} |
||||
|
|
||||
|
public boolean isWritingReply() { |
||||
|
return writingReply; |
||||
|
} |
||||
|
|
||||
|
public void setWritingReply(boolean writingReply) { |
||||
|
this.writingReply = writingReply; |
||||
|
} |
||||
|
|
||||
|
public String getBaseUrl() { |
||||
|
if (topicTaskResult.getValue() != null) { |
||||
|
return topicTaskResult.getValue().getBaseUrl(); |
||||
|
} else { |
||||
|
return ""; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public String getTopicUrl() { |
||||
|
if (topicTaskResult.getValue() != null) { |
||||
|
return topicTaskResult.getValue().getLastPageLoadAttemptedUrl(); |
||||
|
} else { |
||||
|
// topic task has not finished yet (log? disable menu button until load is finished?)
|
||||
|
return firstTopicUrl; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public String getTopicTitle() { |
||||
|
if (topicTaskResult.getValue() == null) |
||||
|
throw new NullPointerException("Topic task has not finished yet!"); |
||||
|
return topicTaskResult.getValue().getTopicTitle(); |
||||
|
} |
||||
|
|
||||
|
public int getCurrentPageIndex() { |
||||
|
if (topicTaskResult.getValue() == null) |
||||
|
throw new NullPointerException("No page has been loaded yet!"); |
||||
|
return topicTaskResult.getValue().getCurrentPageIndex(); |
||||
|
} |
||||
|
|
||||
|
public int getPageCount() { |
||||
|
if (topicTaskResult.getValue() == null) |
||||
|
throw new NullPointerException("No page has been loaded yet!"); |
||||
|
|
||||
|
return topicTaskResult.getValue().getPageCount(); |
||||
|
} |
||||
|
|
||||
|
public String getPostBeingEditedText() { |
||||
|
if (prepareForEditResult.getValue() == null) |
||||
|
throw new NullPointerException("Edit preparation was not found!"); |
||||
|
return prepareForEditResult.getValue().getPostText(); |
||||
|
} |
||||
|
|
||||
|
public String getBuildedQuotes() { |
||||
|
if (prepareForReplyResult.getValue() != null) { |
||||
|
return prepareForReplyResult.getValue().getBuildedQuotes(); |
||||
|
} else { |
||||
|
return ""; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
<vector android:height="24dp" android:tint="#FFFFFF" |
||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0" |
||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
<path android:fillColor="#FF000000" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/> |
||||
|
</vector> |
@ -0,0 +1,118 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginBottom="5dp" |
||||
|
android:paddingEnd="4dp" |
||||
|
android:paddingStart="4dp"> |
||||
|
|
||||
|
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto" |
||||
|
android:id="@+id/card_view" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:layout_gravity="center" |
||||
|
android:foreground="?android:attr/selectableItemBackground" |
||||
|
card_view:cardBackgroundColor="@color/card_background" |
||||
|
card_view:cardCornerRadius="5dp" |
||||
|
card_view:cardElevation="2dp" |
||||
|
card_view:cardPreventCornerOverlap="false" |
||||
|
card_view:cardUseCompatPadding="true"> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<RelativeLayout |
||||
|
android:id="@+id/header" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="0dp" |
||||
|
android:layout_weight="1" |
||||
|
android:clickable="true" |
||||
|
android:focusable="true" |
||||
|
android:paddingLeft="16dp" |
||||
|
android:paddingRight="16dp" |
||||
|
android:paddingTop="16dp"> |
||||
|
|
||||
|
<FrameLayout |
||||
|
android:id="@+id/thumbnail_holder" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_alignParentTop="true" |
||||
|
android:layout_centerVertical="true" |
||||
|
android:layout_marginEnd="16dp"> |
||||
|
|
||||
|
<ImageView |
||||
|
android:id="@+id/thumbnail" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="center" |
||||
|
android:adjustViewBounds="true" |
||||
|
android:contentDescription="@string/post_thumbnail" |
||||
|
android:maxHeight="@dimen/thumbnail_size" |
||||
|
android:maxWidth="@dimen/thumbnail_size" |
||||
|
app:srcCompat="@drawable/ic_default_user_thumbnail_white_24dp" /> |
||||
|
</FrameLayout> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/username" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_alignParentTop="true" |
||||
|
android:layout_toEndOf="@+id/thumbnail_holder" |
||||
|
android:ellipsize="end" |
||||
|
android:maxLines="1" |
||||
|
android:text="@string/post_author" |
||||
|
android:textColor="@color/primary_text" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
<EditText |
||||
|
android:id="@+id/edit_message_subject" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_below="@+id/username" |
||||
|
android:layout_toEndOf="@+id/thumbnail_holder" |
||||
|
android:hint="@string/subject" |
||||
|
android:inputType="textMultiLine" |
||||
|
android:maxLength="80" |
||||
|
android:textSize="10sp" |
||||
|
tools:ignore="SmallSp" /> |
||||
|
</RelativeLayout> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="horizontal" |
||||
|
android:paddingLeft="16dp" |
||||
|
android:paddingRight="16dp"> |
||||
|
|
||||
|
<android.support.design.widget.TextInputLayout |
||||
|
android:layout_width="0dp" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_weight="1" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<EditText |
||||
|
android:id="@+id/edit_message_text" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:hint="@string/post_message" |
||||
|
android:inputType="textMultiLine" /> |
||||
|
</android.support.design.widget.TextInputLayout> |
||||
|
|
||||
|
<android.support.v7.widget.AppCompatImageButton |
||||
|
android:id="@+id/edit_message_submit" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="bottom" |
||||
|
android:layout_marginBottom="5dp" |
||||
|
android:layout_marginEnd="5dp" |
||||
|
android:background="@color/card_background" |
||||
|
android:contentDescription="@string/submit" |
||||
|
app:srcCompat="@drawable/ic_send_accent_24dp" /> |
||||
|
</LinearLayout> |
||||
|
</LinearLayout> |
||||
|
</android.support.v7.widget.CardView> |
||||
|
</FrameLayout> |
Loading…
Reference in new issue