parent
ce88450ee6
commit
b78ccb1b49
@ -1,9 +0,0 @@ |
|||||||
package com.keylesspalace.tusky; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
public interface FetchTimelineListener { |
|
||||||
void onFetchTimelineSuccess(List<Status> statuses, boolean added); |
|
||||||
void onFetchTimelineFailure(IOException e); |
|
||||||
} |
|
@ -1,235 +0,0 @@ |
|||||||
package com.keylesspalace.tusky; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.graphics.Bitmap; |
|
||||||
import android.graphics.BitmapFactory; |
|
||||||
import android.os.AsyncTask; |
|
||||||
import android.os.Build; |
|
||||||
import android.text.Html; |
|
||||||
import android.text.Spanned; |
|
||||||
import android.util.JsonReader; |
|
||||||
import android.util.JsonToken; |
|
||||||
|
|
||||||
import java.io.IOException; |
|
||||||
import java.io.InputStream; |
|
||||||
import java.io.InputStreamReader; |
|
||||||
import java.io.UnsupportedEncodingException; |
|
||||||
import java.net.URL; |
|
||||||
import java.net.URLEncoder; |
|
||||||
import java.text.ParseException; |
|
||||||
import java.text.SimpleDateFormat; |
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Date; |
|
||||||
import java.util.HashMap; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection; |
|
||||||
|
|
||||||
public class FetchTimelineTask extends AsyncTask<String, Void, Boolean> { |
|
||||||
private Context context; |
|
||||||
private FetchTimelineListener fetchTimelineListener; |
|
||||||
private String domain; |
|
||||||
private String accessToken; |
|
||||||
private String fromId; |
|
||||||
private List<com.keylesspalace.tusky.Status> statuses; |
|
||||||
private IOException ioException; |
|
||||||
|
|
||||||
public FetchTimelineTask( |
|
||||||
Context context, FetchTimelineListener listener, String domain, String accessToken, |
|
||||||
String fromId) { |
|
||||||
super(); |
|
||||||
this.context = context; |
|
||||||
fetchTimelineListener = listener; |
|
||||||
this.domain = domain; |
|
||||||
this.accessToken = accessToken; |
|
||||||
this.fromId = fromId; |
|
||||||
} |
|
||||||
|
|
||||||
private Date parseDate(String dateTime) { |
|
||||||
Date date; |
|
||||||
String s = dateTime.replace("Z", "+00:00"); |
|
||||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); |
|
||||||
try { |
|
||||||
date = format.parse(s); |
|
||||||
} catch (ParseException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
return date; |
|
||||||
} |
|
||||||
|
|
||||||
private CharSequence trimTrailingWhitespace(CharSequence s) { |
|
||||||
int i = s.length(); |
|
||||||
do { |
|
||||||
i--; |
|
||||||
} while (i >= 0 && Character.isWhitespace(s.charAt(i))); |
|
||||||
return s.subSequence(0, i + 1); |
|
||||||
} |
|
||||||
|
|
||||||
private Spanned compatFromHtml(String html) { |
|
||||||
Spanned result; |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { |
|
||||||
result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY); |
|
||||||
} else { |
|
||||||
result = Html.fromHtml(html); |
|
||||||
} |
|
||||||
/* Html.fromHtml returns trailing whitespace if the html ends in a </p> tag, which |
|
||||||
* all status contents do, so it should be trimmed. */ |
|
||||||
return (Spanned) trimTrailingWhitespace(result); |
|
||||||
} |
|
||||||
|
|
||||||
private com.keylesspalace.tusky.Status readStatus(JsonReader reader, boolean isReblog) |
|
||||||
throws IOException { |
|
||||||
JsonToken check = reader.peek(); |
|
||||||
if (check == JsonToken.NULL) { |
|
||||||
reader.skipValue(); |
|
||||||
return null; |
|
||||||
} |
|
||||||
String id = null; |
|
||||||
String displayName = null; |
|
||||||
String username = null; |
|
||||||
com.keylesspalace.tusky.Status reblog = null; |
|
||||||
String content = null; |
|
||||||
String avatar = null; |
|
||||||
Date createdAt = null; |
|
||||||
reader.beginObject(); |
|
||||||
while (reader.hasNext()) { |
|
||||||
String name = reader.nextName(); |
|
||||||
switch (name) { |
|
||||||
case "id": { |
|
||||||
id = reader.nextString(); |
|
||||||
break; |
|
||||||
} |
|
||||||
case "account": { |
|
||||||
reader.beginObject(); |
|
||||||
while (reader.hasNext()) { |
|
||||||
name = reader.nextName(); |
|
||||||
switch (name) { |
|
||||||
case "acct": { |
|
||||||
username = reader.nextString(); |
|
||||||
break; |
|
||||||
} |
|
||||||
case "display_name": { |
|
||||||
displayName = reader.nextString(); |
|
||||||
break; |
|
||||||
} |
|
||||||
case "avatar": { |
|
||||||
avatar = reader.nextString(); |
|
||||||
break; |
|
||||||
} |
|
||||||
default: { |
|
||||||
reader.skipValue(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
reader.endObject(); |
|
||||||
break; |
|
||||||
} |
|
||||||
case "reblog": { |
|
||||||
/* This case shouldn't be hit after the first recursion at all. But if this |
|
||||||
* method is passed unusual data this check will prevent extra recursion */ |
|
||||||
if (!isReblog) { |
|
||||||
assert(false); |
|
||||||
reblog = readStatus(reader, true); |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
case "content": { |
|
||||||
content = reader.nextString(); |
|
||||||
break; |
|
||||||
} |
|
||||||
case "created_at": { |
|
||||||
createdAt = parseDate(reader.nextString()); |
|
||||||
break; |
|
||||||
} |
|
||||||
default: { |
|
||||||
reader.skipValue(); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
reader.endObject(); |
|
||||||
assert(username != null); |
|
||||||
com.keylesspalace.tusky.Status status; |
|
||||||
if (reblog != null) { |
|
||||||
status = reblog; |
|
||||||
status.setRebloggedByUsername(username); |
|
||||||
} else { |
|
||||||
assert(content != null); |
|
||||||
Spanned contentPlus = compatFromHtml(content); |
|
||||||
status = new com.keylesspalace.tusky.Status( |
|
||||||
id, displayName, username, contentPlus, avatar, createdAt); |
|
||||||
} |
|
||||||
return status; |
|
||||||
} |
|
||||||
|
|
||||||
private String parametersToQuery(Map<String, String> parameters) |
|
||||||
throws UnsupportedEncodingException { |
|
||||||
StringBuilder s = new StringBuilder(); |
|
||||||
String between = ""; |
|
||||||
for (Map.Entry<String, String> entry : parameters.entrySet()) { |
|
||||||
s.append(between); |
|
||||||
s.append(URLEncoder.encode(entry.getKey(), "UTF-8")); |
|
||||||
s.append("="); |
|
||||||
s.append(URLEncoder.encode(entry.getValue(), "UTF-8")); |
|
||||||
between = "&"; |
|
||||||
} |
|
||||||
String urlParameters = s.toString(); |
|
||||||
return "?" + urlParameters; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected Boolean doInBackground(String... data) { |
|
||||||
Boolean successful = true; |
|
||||||
HttpsURLConnection connection = null; |
|
||||||
try { |
|
||||||
String endpoint = context.getString(R.string.endpoint_timelines_home); |
|
||||||
String query = ""; |
|
||||||
if (fromId != null) { |
|
||||||
Map<String, String> parameters = new HashMap<>(); |
|
||||||
if (fromId != null) { |
|
||||||
parameters.put("max_id", fromId); |
|
||||||
} |
|
||||||
query = parametersToQuery(parameters); |
|
||||||
} |
|
||||||
URL url = new URL("https://" + domain + endpoint + query); |
|
||||||
connection = (HttpsURLConnection) url.openConnection(); |
|
||||||
connection.setRequestMethod("GET"); |
|
||||||
connection.setRequestProperty("Authorization", "Bearer " + accessToken); |
|
||||||
connection.connect(); |
|
||||||
|
|
||||||
statuses = new ArrayList<>(20); |
|
||||||
JsonReader reader = new JsonReader( |
|
||||||
new InputStreamReader(connection.getInputStream(), "UTF-8")); |
|
||||||
reader.beginArray(); |
|
||||||
while (reader.hasNext()) { |
|
||||||
statuses.add(readStatus(reader, false)); |
|
||||||
} |
|
||||||
reader.endArray(); |
|
||||||
reader.close(); |
|
||||||
} catch (IOException e) { |
|
||||||
ioException = e; |
|
||||||
successful = false; |
|
||||||
} finally { |
|
||||||
if (connection != null) { |
|
||||||
connection.disconnect(); |
|
||||||
} |
|
||||||
} |
|
||||||
return successful; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onPostExecute(Boolean wasSuccessful) { |
|
||||||
super.onPostExecute(wasSuccessful); |
|
||||||
if (fetchTimelineListener != null) { |
|
||||||
if (wasSuccessful) { |
|
||||||
fetchTimelineListener.onFetchTimelineSuccess(statuses, fromId != null); |
|
||||||
} else { |
|
||||||
assert(ioException != null); |
|
||||||
fetchTimelineListener.onFetchTimelineFailure(ioException); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue