TODO's have been erradicated.
This commit is contained in:
parent
c1d4bdbdfb
commit
9dceb7a226
9 changed files with 69 additions and 53 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
This is an android client for [Mastodon, a GNU Social-compatible microblogging server](https://mastodon.social). Presently, it is in active development and its current state does not represent the features or design of the final program.
|
This is an android client for [Mastodon, a GNU Social-compatible microblogging server](https://mastodon.social). Presently, it is in active development and its current state does not represent the features or design of the final program.
|
||||||
|
|
||||||
It is currently available for alpha testing on the [Tusky Google Play store page](https://play.google.com/store/apps/details?id=com.keylesspalace.tusky).
|
It is currently available for alpha testing on the Tusky [Google Play store page](https://play.google.com/store/apps/details?id=com.keylesspalace.tusky). You can also find it on F-Droid or at its [F-Droid page](https://f-droid.org/repository/browse/?fdid=com.keylesspalace.tusky).
|
||||||
|
|
||||||
Also, [my mastodon account is Vavassor@mastodon.social](https://mastodon.social/users/Vavassor).
|
Also, [my mastodon account is Vavassor@mastodon.social](https://mastodon.social/users/Vavassor).
|
||||||
|
|
||||||
|
|
|
@ -210,8 +210,14 @@ public class AccountActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onObtainAccountFailure() {
|
private void onObtainAccountFailure() {
|
||||||
//TODO: help
|
Snackbar.make(tabLayout, R.string.error_obtain_account, Snackbar.LENGTH_LONG)
|
||||||
Log.e(TAG, "Failed to obtain that account.");
|
.setAction(R.string.action_retry, new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
obtainAccount();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void obtainRelationships() {
|
private void obtainRelationships() {
|
||||||
|
@ -228,7 +234,7 @@ public class AccountActivity extends BaseActivity {
|
||||||
following = object.getBoolean("following");
|
following = object.getBoolean("following");
|
||||||
blocking = object.getBoolean("blocking");
|
blocking = object.getBoolean("blocking");
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
onObtainRelationshipsFailure();
|
onObtainRelationshipsFailure(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onObtainRelationshipsSuccess(following, blocking);
|
onObtainRelationshipsSuccess(following, blocking);
|
||||||
|
@ -237,7 +243,7 @@ public class AccountActivity extends BaseActivity {
|
||||||
new Response.ErrorListener() {
|
new Response.ErrorListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onErrorResponse(VolleyError error) {
|
public void onErrorResponse(VolleyError error) {
|
||||||
onObtainRelationshipsFailure();
|
onObtainRelationshipsFailure(error);
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -259,9 +265,8 @@ public class AccountActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onObtainRelationshipsFailure() {
|
private void onObtainRelationshipsFailure(Exception exception) {
|
||||||
//TODO: help
|
Log.e(TAG, "Could not obtain relationships. " + exception.getMessage());
|
||||||
Log.e(TAG, "Could not obtain relationships?");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,7 +37,6 @@ import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -54,15 +53,14 @@ public class LoginActivity extends BaseActivity {
|
||||||
* Chain together the key-value pairs into a query string, for either appending to a URL or
|
* Chain together the key-value pairs into a query string, for either appending to a URL or
|
||||||
* as the content of an HTTP request.
|
* as the content of an HTTP request.
|
||||||
*/
|
*/
|
||||||
private String toQueryString(Map<String, String> parameters)
|
private String toQueryString(Map<String, String> parameters) {
|
||||||
throws UnsupportedEncodingException {
|
|
||||||
StringBuilder s = new StringBuilder();
|
StringBuilder s = new StringBuilder();
|
||||||
String between = "";
|
String between = "";
|
||||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||||
s.append(between);
|
s.append(between);
|
||||||
s.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
|
s.append(entry.getKey());
|
||||||
s.append("=");
|
s.append("=");
|
||||||
s.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
|
s.append(entry.getValue());
|
||||||
between = "&";
|
between = "&";
|
||||||
}
|
}
|
||||||
return s.toString();
|
return s.toString();
|
||||||
|
@ -91,15 +89,7 @@ public class LoginActivity extends BaseActivity {
|
||||||
parameters.put("redirect_uri", redirectUri);
|
parameters.put("redirect_uri", redirectUri);
|
||||||
parameters.put("response_type", "code");
|
parameters.put("response_type", "code");
|
||||||
parameters.put("scope", OAUTH_SCOPES);
|
parameters.put("scope", OAUTH_SCOPES);
|
||||||
String queryParameters;
|
String url = "https://" + domain + endpoint + "?" + toQueryString(parameters);
|
||||||
try {
|
|
||||||
queryParameters = toQueryString(parameters);
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
//TODO: No clue how to handle this error case??
|
|
||||||
Log.e(TAG, "Was not able to build the authorization URL.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String url = "https://" + domain + endpoint + "?" + queryParameters;
|
|
||||||
Intent viewIntent = new Intent("android.intent.action.VIEW", Uri.parse(url));
|
Intent viewIntent = new Intent("android.intent.action.VIEW", Uri.parse(url));
|
||||||
startActivity(viewIntent);
|
startActivity(viewIntent);
|
||||||
}
|
}
|
||||||
|
@ -269,9 +259,8 @@ public class LoginActivity extends BaseActivity {
|
||||||
parameters.put("code", code);
|
parameters.put("code", code);
|
||||||
parameters.put("grant_type", "authorization_code");
|
parameters.put("grant_type", "authorization_code");
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
errorText.setText("Heck.");
|
errorText.setText(e.getMessage());
|
||||||
return;
|
return;
|
||||||
//TODO: I don't even know how to handle this error state.
|
|
||||||
}
|
}
|
||||||
String endpoint = getString(R.string.endpoint_token);
|
String endpoint = getString(R.string.endpoint_token);
|
||||||
String url = "https://" + domain + endpoint;
|
String url = "https://" + domain + endpoint;
|
||||||
|
@ -284,9 +273,8 @@ public class LoginActivity extends BaseActivity {
|
||||||
try {
|
try {
|
||||||
accessToken = response.getString("access_token");
|
accessToken = response.getString("access_token");
|
||||||
} catch(JSONException e) {
|
} catch(JSONException e) {
|
||||||
errorText.setText("Heck.");
|
errorText.setText(e.getMessage());
|
||||||
return;
|
return;
|
||||||
//TODO: I don't even know how to handle this error state.
|
|
||||||
}
|
}
|
||||||
onLoginSuccess(accessToken);
|
onLoginSuccess(accessToken);
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,6 @@ public class MainActivity extends BaseActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onFetchUserInfoFailure(Exception exception) {
|
private void onFetchUserInfoFailure(Exception exception) {
|
||||||
//TODO: help
|
|
||||||
Log.e(TAG, "Failed to fetch user info. " + exception.getMessage());
|
Log.e(TAG, "Failed to fetch user info. " + exception.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,6 @@ public class PullNotificationService extends IntentService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCheckNotificationsFailure(Exception exception) {
|
private void onCheckNotificationsFailure(Exception exception) {
|
||||||
//TODO: not sure if just logging here is enough?
|
|
||||||
Log.e(TAG, "Failed to check notifications. " + exception.getMessage());
|
Log.e(TAG, "Failed to check notifications. " + exception.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,8 @@ public class SFragment extends Fragment {
|
||||||
|
|
||||||
protected void sendRequest(
|
protected void sendRequest(
|
||||||
int method, String endpoint, JSONObject parameters,
|
int method, String endpoint, JSONObject parameters,
|
||||||
@Nullable Response.Listener<JSONObject> responseListener) {
|
@Nullable Response.Listener<JSONObject> responseListener,
|
||||||
|
@Nullable Response.ErrorListener errorListener) {
|
||||||
if (responseListener == null) {
|
if (responseListener == null) {
|
||||||
// Use a dummy listener if one wasn't specified so the request can be constructed.
|
// Use a dummy listener if one wasn't specified so the request can be constructed.
|
||||||
responseListener = new Response.Listener<JSONObject>() {
|
responseListener = new Response.Listener<JSONObject>() {
|
||||||
|
@ -82,15 +83,17 @@ public class SFragment extends Fragment {
|
||||||
public void onResponse(JSONObject response) {}
|
public void onResponse(JSONObject response) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (errorListener == null) {
|
||||||
|
errorListener = new Response.ErrorListener() {
|
||||||
|
@Override
|
||||||
|
public void onErrorResponse(VolleyError error) {
|
||||||
|
Log.e(TAG, "Request Failed: " + error.getMessage());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
String url = "https://" + domain + endpoint;
|
String url = "https://" + domain + endpoint;
|
||||||
JsonObjectRequest request = new JsonObjectRequest(
|
JsonObjectRequest request = new JsonObjectRequest(
|
||||||
method, url, parameters, responseListener,
|
method, url, parameters, responseListener, errorListener) {
|
||||||
new Response.ErrorListener() {
|
|
||||||
@Override
|
|
||||||
public void onErrorResponse(VolleyError error) {
|
|
||||||
Log.e(TAG, "Request Failed: " + error.getMessage());
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, String> getHeaders() throws AuthFailureError {
|
public Map<String, String> getHeaders() throws AuthFailureError {
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
@ -103,7 +106,7 @@ public class SFragment extends Fragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void postRequest(String endpoint) {
|
protected void postRequest(String endpoint) {
|
||||||
sendRequest(Request.Method.POST, endpoint, null, null);
|
sendRequest(Request.Method.POST, endpoint, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void reply(Status status) {
|
protected void reply(Status status) {
|
||||||
|
@ -137,7 +140,7 @@ public class SFragment extends Fragment {
|
||||||
status.setReblogged(reblog);
|
status.setReblogged(reblog);
|
||||||
adapter.notifyItemChanged(position);
|
adapter.notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
});
|
}, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void favourite(final Status status, final boolean favourite,
|
protected void favourite(final Status status, final boolean favourite,
|
||||||
|
@ -155,7 +158,7 @@ public class SFragment extends Fragment {
|
||||||
status.setFavourited(favourite);
|
status.setFavourited(favourite);
|
||||||
adapter.notifyItemChanged(position);
|
adapter.notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
});
|
}, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void follow(String id) {
|
private void follow(String id) {
|
||||||
|
@ -170,7 +173,7 @@ public class SFragment extends Fragment {
|
||||||
|
|
||||||
private void delete(String id) {
|
private void delete(String id) {
|
||||||
String endpoint = String.format(getString(R.string.endpoint_delete), id);
|
String endpoint = String.format(getString(R.string.endpoint_delete), id);
|
||||||
sendRequest(Request.Method.DELETE, endpoint, null, null);
|
sendRequest(Request.Method.DELETE, endpoint, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void more(Status status, View view, final AdapterItemRemover adapter,
|
protected void more(Status status, View view, final AdapterItemRemover adapter,
|
||||||
|
|
|
@ -19,6 +19,7 @@ import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.content.ContextCompat;
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v7.widget.DividerItemDecoration;
|
import android.support.v7.widget.DividerItemDecoration;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
@ -29,6 +30,7 @@ import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.android.volley.Request;
|
import com.android.volley.Request;
|
||||||
import com.android.volley.Response;
|
import com.android.volley.Response;
|
||||||
|
import com.android.volley.VolleyError;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
@ -36,8 +38,6 @@ import org.json.JSONObject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ViewThreadFragment extends SFragment implements StatusActionListener {
|
public class ViewThreadFragment extends SFragment implements StatusActionListener {
|
||||||
private static final String TAG = "ViewThread"; // logging tag
|
|
||||||
|
|
||||||
private RecyclerView recyclerView;
|
private RecyclerView recyclerView;
|
||||||
private ThreadAdapter adapter;
|
private ThreadAdapter adapter;
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendStatusRequest(String id) {
|
private void sendStatusRequest(final String id) {
|
||||||
String endpoint = String.format(getString(R.string.endpoint_get_status), id);
|
String endpoint = String.format(getString(R.string.endpoint_get_status), id);
|
||||||
super.sendRequest(Request.Method.GET, endpoint, null,
|
super.sendRequest(Request.Method.GET, endpoint, null,
|
||||||
new Response.Listener<JSONObject>() {
|
new Response.Listener<JSONObject>() {
|
||||||
|
@ -85,16 +85,22 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
|
||||||
try {
|
try {
|
||||||
status = Status.parse(response, false);
|
status = Status.parse(response, false);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
onThreadRequestFailure();
|
onThreadRequestFailure(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int position = adapter.insertStatus(status);
|
int position = adapter.insertStatus(status);
|
||||||
recyclerView.scrollToPosition(position);
|
recyclerView.scrollToPosition(position);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
new Response.ErrorListener() {
|
||||||
|
@Override
|
||||||
|
public void onErrorResponse(VolleyError error) {
|
||||||
|
onThreadRequestFailure(id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendThreadRequest(String id) {
|
private void sendThreadRequest(final String id) {
|
||||||
String endpoint = String.format(getString(R.string.endpoint_context), id);
|
String endpoint = String.format(getString(R.string.endpoint_context), id);
|
||||||
super.sendRequest(Request.Method.GET, endpoint, null,
|
super.sendRequest(Request.Method.GET, endpoint, null,
|
||||||
new Response.Listener<JSONObject>() {
|
new Response.Listener<JSONObject>() {
|
||||||
|
@ -108,15 +114,28 @@ public class ViewThreadFragment extends SFragment implements StatusActionListene
|
||||||
adapter.addAncestors(ancestors);
|
adapter.addAncestors(ancestors);
|
||||||
adapter.addDescendants(descendants);
|
adapter.addDescendants(descendants);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
onThreadRequestFailure();
|
onThreadRequestFailure(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
new Response.ErrorListener() {
|
||||||
|
@Override
|
||||||
|
public void onErrorResponse(VolleyError error) {
|
||||||
|
onThreadRequestFailure(id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onThreadRequestFailure() {
|
private void onThreadRequestFailure(final String id) {
|
||||||
Log.e(TAG, "The request to fetch the thread has failed.");
|
Snackbar.make(recyclerView, R.string.error_view_thread, Snackbar.LENGTH_LONG)
|
||||||
//TODO: no
|
.setAction(R.string.action_retry, new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
sendThreadRequest(id);
|
||||||
|
sendStatusRequest(id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onReply(int position) {
|
public void onReply(int position) {
|
||||||
|
|
|
@ -26,7 +26,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/blocked_user_display_name"
|
android:id="@+id/blocked_user_display_name"
|
||||||
android:text="Display Name" />
|
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Small"
|
||||||
|
android:textStyle="normal|bold" />
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -37,7 +38,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:id="@+id/blocked_user_username"
|
android:id="@+id/blocked_user_username"
|
||||||
android:text="\@username\@example.com" />
|
android:textColor="?attr/status_text_color_secondary" />
|
||||||
|
|
||||||
<Space
|
<Space
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
<string name="error_unfollowing">That user wasn\'t unfollowed.</string>
|
<string name="error_unfollowing">That user wasn\'t unfollowed.</string>
|
||||||
<string name="error_blocking">That user wasn\'t blocked.</string>
|
<string name="error_blocking">That user wasn\'t blocked.</string>
|
||||||
<string name="error_unblocking">That user wasn\'t unblocked.</string>
|
<string name="error_unblocking">That user wasn\'t unblocked.</string>
|
||||||
|
<string name="error_view_thread">Couldn\'t fetch that thread.</string>
|
||||||
|
<string name="error_obtain_account">Failed to obtain that account.</string>
|
||||||
|
|
||||||
<string name="title_home">Home</string>
|
<string name="title_home">Home</string>
|
||||||
<string name="title_notifications">Notifications</string>
|
<string name="title_notifications">Notifications</string>
|
||||||
|
@ -86,7 +88,7 @@
|
||||||
<string name="notification_follow_format">%s followed you</string>
|
<string name="notification_follow_format">%s followed you</string>
|
||||||
|
|
||||||
<string name="action_compose">Compose</string>
|
<string name="action_compose">Compose</string>
|
||||||
<string name="action_login">Log In</string>
|
<string name="action_login">Ask Site To Log In</string>
|
||||||
<string name="action_logout">Log Out</string>
|
<string name="action_logout">Log Out</string>
|
||||||
<string name="action_follow">Follow</string>
|
<string name="action_follow">Follow</string>
|
||||||
<string name="action_unfollow">Unfollow</string>
|
<string name="action_unfollow">Unfollow</string>
|
||||||
|
@ -110,7 +112,7 @@
|
||||||
|
|
||||||
<string name="confirmation_send">Toot!</string>
|
<string name="confirmation_send">Toot!</string>
|
||||||
|
|
||||||
<string name="hint_domain">example.com</string>
|
<string name="hint_domain">Which Site?</string>
|
||||||
<string name="hint_compose">What\'s Happening?</string>
|
<string name="hint_compose">What\'s Happening?</string>
|
||||||
<string name="hint_content_warning">Beware, folks</string>
|
<string name="hint_content_warning">Beware, folks</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue