finalized AsyncTask replacement, gradle dependency update

This commit is contained in:
nuclearfog 2023-02-19 22:04:05 +01:00
parent 32d39de898
commit b4cd439eaf
No known key found for this signature in database
GPG Key ID: 03488A185C476379
47 changed files with 1461 additions and 1443 deletions

View File

@ -54,7 +54,7 @@ proguardDictionaries {
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

View File

@ -165,57 +165,65 @@ public interface Connection {
* follow a specific user
*
* @param id ID of the user
* @return updated relation to the user
*/
void followUser(long id) throws ConnectionException;
Relation followUser(long id) throws ConnectionException;
/**
* unfollow a specific user
*
* @param id ID of the user
* @return updated relation to the user
*/
void unfollowUser(long id) throws ConnectionException;
Relation unfollowUser(long id) throws ConnectionException;
/**
* block specific user
*
* @param id ID of the user
* @return updated relation to the user
*/
void blockUser(long id) throws ConnectionException;
Relation blockUser(long id) throws ConnectionException;
/**
* block specific user
*
* @param name screen name of the user
* @return updated relation to the user
*/
void blockUser(String name) throws ConnectionException;
Relation blockUser(String name) throws ConnectionException;
/**
* unblock specific user
*
* @param id ID of the user
* @return updated relation to the user
*/
void unblockUser(long id) throws ConnectionException;
Relation unblockUser(long id) throws ConnectionException;
/**
* mute specific user
*
* @param id ID of the user
* @return updated relation to the user
*/
void muteUser(long id) throws ConnectionException;
Relation muteUser(long id) throws ConnectionException;
/**
* mute specific user
*
* @param name screen name of the user
* @return updated relation to the user
*/
void muteUser(String name) throws ConnectionException;
Relation muteUser(String name) throws ConnectionException;
/**
* mute specific user
*
* @param id ID of the user
* @return updated relation to the user
*/
void unmuteUser(long id) throws ConnectionException;
Relation unmuteUser(long id) throws ConnectionException;
/**
* search statuses matching a search string

View File

@ -18,26 +18,6 @@ import org.nuclearfog.twidda.config.GlobalSettings.OnSettingsChangeListener;
*/
public class ConnectionManager {
/**
* select connection to a social network automatically
*/
public static final int SELECT_AUTO = 0;
/**
* select Twitter connection
*/
public static final int SELECT_TWITTER_1 = 1;
/**
* select Twitter connection
*/
public static final int SELECT_TWITTER_2 = 2;
/**
* select Mastodon connection
*/
public static final int SELECT_MASTODON = 3;
private static Connection connection;
private static boolean notifySettingsChange = false;

View File

@ -293,7 +293,7 @@ public class Mastodon implements Connection {
@Override
public Relation getUserRelationship(long id) throws MastodonException {
public MastodonRelation getUserRelationship(long id) throws MastodonException {
List<String> params = new ArrayList<>();
params.add("id[]=" + id);
try {
@ -301,7 +301,7 @@ public class Mastodon implements Connection {
ResponseBody body = response.body();
if (response.code() == 200 && body != null) {
JSONArray array = new JSONArray(body.string());
return new MastodonRelation(array.getJSONObject(0), settings.getLogin().getId());
return new MastodonRelation(array.getJSONObject(0));
}
throw new MastodonException(response);
} catch (IOException | JSONException e) {
@ -311,52 +311,76 @@ public class Mastodon implements Connection {
@Override
public void followUser(long id) throws MastodonException {
public Relation followUser(long id) throws MastodonException {
createPost(ENDPOINT_ACCOUNTS + id + "/follow", new ArrayList<>());
MastodonRelation relation = getUserRelationship(id);
relation.setFollowing(true);
return relation;
}
@Override
public void unfollowUser(long id) throws MastodonException {
public Relation unfollowUser(long id) throws MastodonException {
createPost(ENDPOINT_ACCOUNTS + id + "/unfollow", new ArrayList<>());
MastodonRelation relation = getUserRelationship(id);
relation.setFollowing(false);
return relation;
}
@Override
public void blockUser(long id) throws MastodonException {
public Relation blockUser(long id) throws MastodonException {
createPost(ENDPOINT_ACCOUNTS + id + "/block", new ArrayList<>());
MastodonRelation relation = getUserRelationship(id);
relation.setBlocked(true);
return relation;
}
@Override
public void blockUser(String name) throws MastodonException {
public Relation blockUser(String name) throws MastodonException {
User user = showUser(name);
blockUser(user.getId());
MastodonRelation relation = getUserRelationship(user.getId());
relation.setBlocked(true);
return relation;
}
@Override
public void unblockUser(long id) throws MastodonException {
public Relation unblockUser(long id) throws MastodonException {
createPost(ENDPOINT_ACCOUNTS + id + "/unblock", new ArrayList<>());
MastodonRelation relation = getUserRelationship(id);
relation.setBlocked(false);
return relation;
}
@Override
public void muteUser(long id) throws MastodonException {
public Relation muteUser(long id) throws MastodonException {
createPost(ENDPOINT_ACCOUNTS + id + "/mute", new ArrayList<>());
MastodonRelation relation = getUserRelationship(id);
relation.setMuted(true);
return relation;
}
@Override
public void muteUser(String name) throws MastodonException {
public Relation muteUser(String name) throws MastodonException {
User user = showUser(name);
muteUser(user.getId());
MastodonRelation relation = getUserRelationship(user.getId());
relation.setMuted(false);
return relation;
}
@Override
public void unmuteUser(long id) throws MastodonException {
public Relation unmuteUser(long id) throws MastodonException {
createPost(ENDPOINT_ACCOUNTS + id + "/unmute", new ArrayList<>());
MastodonRelation relation = getUserRelationship(id);
relation.setMuted(false);
return relation;
}
@ -491,42 +515,48 @@ public class Mastodon implements Connection {
@Override
public Status favoriteStatus(long id) throws MastodonException {
return postStatus(ENDPOINT_STATUS + id + "/favourite", new ArrayList<>());
MastodonStatus status = postStatus(ENDPOINT_STATUS + id + "/favourite", new ArrayList<>());
status.setFavorite(true);
return status;
}
@Override
public Status unfavoriteStatus(long id) throws MastodonException {
MastodonStatus status = postStatus(ENDPOINT_STATUS + id + "/unfavourite", new ArrayList<>());
status.unfavorite();
status.setFavorite(false);
return status;
}
@Override
public Status repostStatus(long id) throws MastodonException {
return postStatus(ENDPOINT_STATUS + id + "/reblog", new ArrayList<>());
MastodonStatus status = postStatus(ENDPOINT_STATUS + id + "/reblog", new ArrayList<>());
status.setRepost(true);
return status;
}
@Override
public Status removeRepost(long id) throws MastodonException {
MastodonStatus status = postStatus(ENDPOINT_STATUS + id + "/unreblog", new ArrayList<>());
status.unreblog();
status.setRepost(false);
return status;
}
@Override
public Status bookmarkStatus(long id) throws ConnectionException {
return postStatus(ENDPOINT_STATUS + id + "/bookmark", new ArrayList<>());
MastodonStatus status = postStatus(ENDPOINT_STATUS + id + "/bookmark", new ArrayList<>());
status.setBookmark(true);
return status;
}
@Override
public Status removeBookmark(long id) throws ConnectionException {
MastodonStatus status = postStatus(ENDPOINT_STATUS + id + "/unbookmark", new ArrayList<>());
status.removeBookmark();
status.setBookmark(false);
return status;
}

View File

@ -15,24 +15,23 @@ public class MastodonRelation implements Relation {
private static final long serialVersionUID = -3824807644551732407L;
private boolean currentUser;
private boolean following;
private boolean follower;
private boolean blocked;
private boolean muted;
private long id;
private boolean isFollowing;
private boolean isFollower;
private boolean isBlocked;
private boolean isMuted;
/**
* @param json Relation json object
* @param currentId ID of the current user
*/
public MastodonRelation(JSONObject json, long currentId) throws JSONException {
public MastodonRelation(JSONObject json) throws JSONException {
String idStr = json.getString("id");
following = json.optBoolean("following");
follower = json.optBoolean("followed_by");
blocked = json.optBoolean("blocking");
muted = json.optBoolean("muting");
isFollowing = json.optBoolean("following");
isFollower = json.optBoolean("followed_by");
isBlocked = json.optBoolean("blocking");
isMuted = json.optBoolean("muting");
try {
currentUser = currentId == Long.parseLong(idStr);
id = Long.parseLong(idStr);
} catch (NumberFormatException e) {
throw new JSONException("bad ID:" + idStr);
}
@ -40,32 +39,32 @@ public class MastodonRelation implements Relation {
@Override
public boolean isCurrentUser() {
return currentUser;
public long getId() {
return id;
}
@Override
public boolean isFollowing() {
return following;
return isFollowing;
}
@Override
public boolean isFollower() {
return follower;
return isFollower;
}
@Override
public boolean isBlocked() {
return blocked;
return isBlocked;
}
@Override
public boolean isMuted() {
return muted;
return isMuted;
}
@ -75,10 +74,25 @@ public class MastodonRelation implements Relation {
}
public void setFollowing(boolean isFollowing) {
this.isFollowing = isFollowing;
}
public void setBlocked(boolean isBlocked) {
this.isBlocked = isBlocked;
}
public void setMuted(boolean isMuted) {
this.isMuted = isMuted;
}
@NonNull
@Override
public String toString() {
return "following=" + following + " follower=" + follower +
" blocked=" + blocked + " muted=" + muted;
return "following=" + isFollowing + " follower=" + isFollower +
" blocked=" + isBlocked + " muted=" + isMuted;
}
}

View File

@ -35,7 +35,7 @@ public class MastodonStatus implements Status {
private int favoriteCount;
private int reblogCount;
private boolean favorited;
private boolean reblogged;
private boolean reposted;
private boolean bookmarked;
private boolean sensitive;
private boolean muted;
@ -75,7 +75,7 @@ public class MastodonStatus implements Status {
favoriteCount = json.optInt("favourites_count");
muted = json.optBoolean("muted", false);
favorited = json.optBoolean("favourited", false);
reblogged = json.optBoolean("reblogged", false);
reposted = json.optBoolean("reblogged", false);
sensitive = json.optBoolean("sensitive", false);
bookmarked = json.optBoolean("bookmarked", false);
text = json.optString("content", "");
@ -248,7 +248,7 @@ public class MastodonStatus implements Status {
@Override
public boolean isReposted() {
return reblogged;
return reposted;
}
@ -326,38 +326,38 @@ public class MastodonStatus implements Status {
}
/**
* correct retweet count
* set repost status
*/
public void unreblog() {
public void setRepost(boolean reposted) {
this.reposted = reposted;
if (embeddedStatus instanceof MastodonStatus) {
((MastodonStatus) embeddedStatus).unreblog();
((MastodonStatus) embeddedStatus).setRepost(reposted);
}
if (reblogCount > 0) {
if (!reposted && reblogCount > 0) {
reblogCount--;
}
reblogged = false;
}
/**
* correct favorite count
* set favorite status
*/
public void unfavorite() {
public void setFavorite(boolean favorited) {
this.favorited = favorited;
if (embeddedStatus instanceof MastodonStatus) {
((MastodonStatus) embeddedStatus).unfavorite();
((MastodonStatus) embeddedStatus).setFavorite(favorited);
}
if (favoriteCount > 0) {
if (!favorited && favoriteCount > 0) {
favoriteCount--;
}
favorited = false;
}
/**
* remove status bookmark
* set bookmark status
*/
public void removeBookmark() {
public void setBookmark(boolean bookmarked) {
this.bookmarked = bookmarked;
if (embeddedStatus instanceof MastodonStatus) {
((MastodonStatus) embeddedStatus).removeBookmark();
((MastodonStatus) embeddedStatus).setBookmark(bookmarked);
}
bookmarked = false;
}
}

View File

@ -15,7 +15,7 @@ public class RelationV1 implements Relation {
private static final long serialVersionUID = -1595992003137510951L;
private boolean isCurrentUser;
private long id;
private boolean isFollowing;
private boolean isFollower;
private boolean isBlocked;
@ -32,44 +32,70 @@ public class RelationV1 implements Relation {
String sourceIdStr = source.getString("id_str");
String targetIdStr = target.getString("id_str");
isCurrentUser = sourceIdStr.equals(targetIdStr);
isFollowing = source.optBoolean("following");
isFollower = source.optBoolean("followed_by");
isBlocked = source.optBoolean("blocking");
isMuted = source.optBoolean("muting");
canDm = source.optBoolean("can_dm");
try {
id = Long.parseLong(targetIdStr);
} catch (NumberFormatException e) {
throw new JSONException("bad ID: " + sourceIdStr);
}
}
@Override
public boolean isCurrentUser() {
return isCurrentUser;
public long getId() {
return id;
}
@Override
public boolean isFollowing() {
return isFollowing;
}
@Override
public boolean isFollower() {
return isFollower;
}
@Override
public boolean isBlocked() {
return isBlocked;
}
@Override
public boolean isMuted() {
return isMuted;
}
@Override
public boolean canDm() {
return canDm;
}
public void setFollowing(boolean isFollowing) {
this.isFollowing = isFollowing;
}
public void setMuted(boolean isMuted) {
this.isMuted = isMuted;
}
public void setBlocked(boolean isBlocked) {
this.isBlocked = isBlocked;
}
@NonNull
@Override
public String toString() {

View File

@ -386,7 +386,7 @@ public class TwitterV1 implements Connection {
@Override
public Relation getUserRelationship(long id) throws TwitterException {
public RelationV1 getUserRelationship(long id) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("source_id=" + settings.getLogin().getId());
params.add("target_id=" + id);
@ -405,70 +405,94 @@ public class TwitterV1 implements Connection {
@Override
public void followUser(long id) throws TwitterException {
public Relation followUser(long id) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
getUser(USER_FOLLOW, params);
RelationV1 relation = getUserRelationship(id);
relation.setFollowing(true);
return relation;
}
@Override
public void unfollowUser(long id) throws TwitterException {
public Relation unfollowUser(long id) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
getUser(USER_UNFOLLOW, params);
RelationV1 relation = getUserRelationship(id);
relation.setFollowing(false);
return relation;
}
@Override
public void blockUser(long id) throws TwitterException {
public Relation blockUser(long id) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
getUser(USER_BLOCK, params);
RelationV1 relation = getUserRelationship(id);
relation.setBlocked(true);
return relation;
}
@Override
public void blockUser(String name) throws TwitterException {
public Relation blockUser(String name) throws TwitterException {
List<String> params = new ArrayList<>();
if (name.startsWith("@"))
name = name.substring(1);
params.add("screen_name=" + StringTools.encode(name));
getUser(USER_BLOCK, params);
User user = getUser(USER_BLOCK, params);
RelationV1 relation = getUserRelationship(user.getId());
relation.setBlocked(true);
return relation;
}
@Override
public void unblockUser(long id) throws TwitterException {
public Relation unblockUser(long id) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
getUser(USER_UNBLOCK, params);
RelationV1 relation = getUserRelationship(id);
relation.setBlocked(false);
return relation;
}
@Override
public void muteUser(long id) throws TwitterException {
public Relation muteUser(long id) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
getUser(USER_MUTE, params);
RelationV1 relation = getUserRelationship(id);
relation.setMuted(true);
return relation;
}
@Override
public void muteUser(String name) throws TwitterException {
public Relation muteUser(String name) throws TwitterException {
List<String> params = new ArrayList<>();
if (name.startsWith("@"))
name = name.substring(1);
params.add("screen_name=" + StringTools.encode(name));
getUser(USER_MUTE, params);
User user = getUser(USER_MUTE, params);
RelationV1 relation = getUserRelationship(user.getId());
relation.setMuted(true);
return relation;
}
@Override
public void unmuteUser(long id) throws TwitterException {
public Relation unmuteUser(long id) throws TwitterException {
List<String> params = new ArrayList<>();
params.add("user_id=" + id);
getUser(USER_UNMUTE, params);
RelationV1 relation = getUserRelationship(id);
relation.setMuted(false);
return relation;
}

View File

@ -17,19 +17,11 @@ import java.util.List;
*/
public class AccountLoader extends AsyncExecutor<AccountLoader.AccountParameter, AccountLoader.AccountResult> {
/**
* load all saved logins
*/
public static final int MODE_LOAD = 1;
/**
* delete specific login
*/
public static final int MODE_DELETE = 2;
private AppDatabase db;
/**
*
*/
public AccountLoader(Context context) {
db = new AppDatabase(context);
}
@ -40,13 +32,13 @@ public class AccountLoader extends AsyncExecutor<AccountLoader.AccountParameter,
protected AccountResult doInBackground(AccountParameter request) {
try {
switch (request.mode) {
case MODE_LOAD:
case AccountParameter.LOAD:
List<Account> accounts = db.getLogins();
return new AccountResult(request.mode, 0L, accounts);
return new AccountResult(AccountResult.LOAD, 0L, accounts);
case MODE_DELETE:
case AccountParameter.DELETE:
db.removeLogin(request.id);
return new AccountResult(request.mode, request.id, null);
return new AccountResult(AccountResult.DELETE, request.id, null);
}
} catch (Exception e) {
e.printStackTrace();
@ -57,6 +49,9 @@ public class AccountLoader extends AsyncExecutor<AccountLoader.AccountParameter,
public static class AccountParameter {
public static final int LOAD = 1;
public static final int DELETE = 2;
public final int mode;
public final long id;
@ -69,6 +64,9 @@ public class AccountLoader extends AsyncExecutor<AccountLoader.AccountParameter,
public static class AccountResult {
public static final int LOAD = 3;
public static final int DELETE = 4;
@Nullable
public final List<Account> accounts;
public final int mode;

View File

@ -10,6 +10,7 @@ import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.Relation;
import org.nuclearfog.twidda.ui.activities.UsersActivity;
import java.util.List;
@ -23,30 +24,12 @@ import java.util.List;
*/
public class FilterLoader extends AsyncExecutor<FilterLoader.FilterParam, FilterLoader.FilterResult> {
/**
* refresh exclude list
*/
public static final int MODE_RELOAD = 1;
/**
* mute specified user
*/
public static final int MODE_MUTE = 2;
/**
* block specified user
*/
public static final int MODE_BLOCK = 3;
/**
* error occured
*/
public static final int MODE_ERROR = -1;
private Connection connection;
private AppDatabase db;
/**
*
*/
public FilterLoader(Context context) {
connection = ConnectionManager.get(context);
db = new AppDatabase(context);
@ -58,31 +41,36 @@ public class FilterLoader extends AsyncExecutor<FilterLoader.FilterParam, Filter
protected FilterResult doInBackground(FilterParam param) {
try {
switch (param.mode) {
case MODE_RELOAD:
case FilterParam.RELOAD:
List<Long> ids = connection.getIdBlocklist();
db.setFilterlistUserIds(ids);
break;
return new FilterResult(FilterResult.RELOAD, null);
case MODE_MUTE:
connection.muteUser(param.name);
break;
case FilterParam.MUTE:
Relation relation = connection.muteUser(param.name);
db.muteUser(relation.getId(), true);
return new FilterResult(FilterResult.MUTE, null);
case MODE_BLOCK:
connection.blockUser(param.name);
break;
case FilterParam.BLOCK:
relation = connection.blockUser(param.name);
db.muteUser(relation.getId(), true);
return new FilterResult(FilterResult.BLOCK, null);
}
return new FilterResult(param.mode, null);
} catch (ConnectionException exception) {
return new FilterResult(MODE_ERROR, exception);
return new FilterResult(FilterResult.ERROR, exception);
} catch (Exception e) {
e.printStackTrace();
}
return new FilterResult(MODE_ERROR, null);
return new FilterResult(FilterResult.ERROR, null);
}
public static class FilterParam {
public static final int RELOAD = 1;
public static final int MUTE = 2;
public static final int BLOCK = 3;
public final String name;
public final int mode;
@ -100,6 +88,11 @@ public class FilterLoader extends AsyncExecutor<FilterLoader.FilterParam, Filter
public static class FilterResult {
public static final int RELOAD = 4;
public static final int MUTE = 5;
public static final int BLOCK = 6;
public static final int ERROR = -1;
public final int mode;
@Nullable
public final ConnectionException exception;

View File

@ -19,7 +19,7 @@ import java.io.FileOutputStream;
import java.io.InputStream;
/**
* This AsyncTask class downloads images to a local cache folder
* This class downloads images to a local cache folder
* and creates Uri of the images.
*
* @author nuclearfog
@ -99,8 +99,4 @@ public class ImageLoader extends AsyncExecutor<ImageLoader.ImageParameter, Image
this.uri = uri;
}
}
public interface ImageCallback extends AsyncCallback<ImageResult> {
}
}

View File

@ -9,7 +9,7 @@ import java.io.InputStream;
import java.io.OutputStream;
/**
* This AsyncTask class moves a cached image to the destiny folder
* This class moves a downloaded image to the destiny folder
*
* @author nuclearfog
* @see MediaActivity

View File

@ -1,8 +1,8 @@
package org.nuclearfog.twidda.backend.async;
import android.app.Activity;
import android.content.Context;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.annotation.NonNull;
@ -11,6 +11,7 @@ import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.model.UserList;
import org.nuclearfog.twidda.ui.activities.MainActivity;
@ -21,7 +22,6 @@ import org.nuclearfog.twidda.ui.activities.StatusEditor;
import org.nuclearfog.twidda.ui.activities.UserlistActivity;
import org.nuclearfog.twidda.ui.activities.UserlistsActivity;
import java.lang.ref.WeakReference;
import java.util.List;
/**
@ -33,26 +33,23 @@ import java.util.List;
* @author nuclearfog
* @see MainActivity
*/
public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
public class LinkLoader extends AsyncExecutor<Uri, LinkLoader.LinkResult> {
private WeakReference<MainActivity> weakRef;
private Connection connection;
@Nullable
private ConnectionException exception;
public LinkLoader(MainActivity activity) {
super();
weakRef = new WeakReference<>(activity);
connection = ConnectionManager.get(activity);
/**
*
*/
public LinkLoader(Context context) {
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected DataHolder doInBackground(Uri... links) {
protected LinkResult doInBackground(Uri link) {
try {
Uri link = links[0];
List<String> pathSeg = link.getPathSegments();
Bundle data = new Bundle();
if (!pathSeg.isEmpty()) {
@ -60,26 +57,26 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
// e.g. twitter.com/home
if (pathSeg.get(0).equals("home")) {
data.putInt(MainActivity.KEY_TAB_PAGE, 0);
return new DataHolder(data, MainActivity.class);
return new LinkResult(data, MainActivity.class);
}
// open trend tab
// e.g. twitter.com/trends , twitter.com/explore or twitter.com/i/trends
else if (pathSeg.get(0).equals("trends") || pathSeg.get(0).equals("explore") ||
(pathSeg.size() == 2 && pathSeg.get(0).equals("i") && pathSeg.get(1).equals("trends"))) {
data.putInt(MainActivity.KEY_TAB_PAGE, 1);
return new DataHolder(data, MainActivity.class);
return new LinkResult(data, MainActivity.class);
}
// open mentions timeline
// e.g. twitter.com/notifications
else if (pathSeg.get(0).equals("notifications")) {
data.putInt(MainActivity.KEY_TAB_PAGE, 2);
return new DataHolder(data, MainActivity.class);
return new LinkResult(data, MainActivity.class);
}
// open directmessage page
// e.g. twitter.com/messages
else if (pathSeg.get(0).equals("messages")) {
data.putInt(MainActivity.KEY_TAB_PAGE, 3);
return new DataHolder(data, MainActivity.class);
return new LinkResult(data, MainActivity.class);
}
// open twitter search
// e.g. twitter.com/search?q={search string}
@ -88,7 +85,7 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
String search = link.getQueryParameter("q");
if (search != null) {
data.putString(SearchActivity.KEY_SEARCH_QUERY, search);
return new DataHolder(data, SearchActivity.class);
return new LinkResult(data, SearchActivity.class);
}
}
}
@ -108,7 +105,7 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
if (via != null)
status += "via @" + via;
data.putString(StatusEditor.KEY_STATUS_EDITOR_TEXT, status);
return new DataHolder(data, StatusEditor.class);
return new LinkResult(data, StatusEditor.class);
}
}
// open hashtag search
@ -116,7 +113,7 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
else if (pathSeg.size() == 2 && pathSeg.get(0).equals("hashtag")) {
String search = '#' + pathSeg.get(1);
data.putString(SearchActivity.KEY_SEARCH_QUERY, search);
return new DataHolder(data, SearchActivity.class);
return new LinkResult(data, SearchActivity.class);
}
// open an userlist
// e.g. twitter.com/i/lists/{list id}
@ -125,7 +122,7 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
UserList list = connection.getUserlist(listId);
data.putSerializable(UserlistActivity.KEY_LIST_DATA, list);
data.putBoolean(UserlistActivity.KEY_LIST_NO_UPDATE, true);
return new DataHolder(data, UserlistActivity.class);
return new LinkResult(data, UserlistActivity.class);
}
// show status
// e.g. twitter.com/{screenname}/status/{tweet ID}
@ -134,7 +131,7 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
long Id = Long.parseLong(pathSeg.get(2));
data.putLong(StatusActivity.KEY_STATUS_ID, Id);
data.putString(StatusActivity.KEY_STATUS_NAME, screenname);
return new DataHolder(data, StatusActivity.class);
return new LinkResult(data, StatusActivity.class);
}
// show userlists
// e.g. twitter.com/{screenname}/lists
@ -142,7 +139,7 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
String screenname = pathSeg.get(0);
User user = connection.showUser(screenname);
data.putLong(UserlistsActivity.KEY_USERLIST_OWNER_ID, user.getId());
return new DataHolder(data, UserlistsActivity.class);
return new LinkResult(data, UserlistsActivity.class);
}
// show user profile
// e.g. twitter.com/{screenname}
@ -151,43 +148,37 @@ public class LinkLoader extends AsyncTask<Uri, Void, LinkLoader.DataHolder> {
String screenname = pathSeg.get(0);
User user = connection.showUser(screenname);
data.putSerializable(ProfileActivity.KEY_PROFILE_USER, user);
data.putBoolean(ProfileActivity.KEY_PROFILE_DISABLE_RELOAD, true);
return new DataHolder(data, ProfileActivity.class);
return new LinkResult(data, ProfileActivity.class);
}
}
} catch (ConnectionException exception) {
this.exception = exception;
return new LinkResult(null, null, exception);
} catch (Exception e) {
e.printStackTrace();
}
return null;
return new LinkResult(null, null, null);
}
@Override
protected void onPostExecute(@Nullable DataHolder result) {
MainActivity activity = weakRef.get();
if (activity != null) {
if (result != null) {
activity.onSuccess(result);
} else {
activity.onError(exception);
}
}
}
/**
* Holder class for information to start an activity
*/
public static class DataHolder {
@NonNull
public final Bundle data;
public final Class<? extends Activity> activity;
public static class LinkResult {
DataHolder(@NonNull Bundle data, Class<? extends Activity> activity) {
@Nullable
public final Bundle data;
@Nullable
public final Class<? extends Activity> activity;
@Nullable
public final ConnectionException exception;
public LinkResult(@NonNull Bundle data, @Nullable Class<? extends Activity> activity) {
this(data, activity, null);
}
LinkResult(@Nullable Bundle data, @Nullable Class<? extends Activity> activity, @Nullable ConnectionException exception) {
this.data = data;
this.activity = activity;
this.exception = exception;
}
}
}

View File

@ -1,100 +1,100 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.model.UserList;
import org.nuclearfog.twidda.ui.activities.UserlistActivity;
import java.lang.ref.WeakReference;
/**
* async task to load list information and take action to the list
*
* @author nuclearfog
*/
public class ListAction extends AsyncTask<Void, Void, UserList> {
public class ListAction extends AsyncExecutor<ListAction.ListActionParam, ListAction.ListActionResult> {
/**
* load userlist information
*/
public static final int LOAD = 1;
/**
* unfollow user list
*/
public static final int FOLLOW = 2;
/**
* unfollow user list
*/
public static final int UNFOLLOW = 3;
/**
* delete user list
*/
public static final int DELETE = 4;
private WeakReference<UserlistActivity> weakRef;
private Connection connection;
private ConnectionException exception;
private long listId;
private int action;
/**
* @param activity Callback to update list information
* @param listId ID of the list to process
* @param action what action should be performed
*
*/
public ListAction(UserlistActivity activity, long listId, int action) {
super();
weakRef = new WeakReference<>(activity);
connection = ConnectionManager.get(activity);
this.listId = listId;
this.action = action;
public ListAction(Context context) {
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected UserList doInBackground(Void... v) {
protected ListActionResult doInBackground(ListActionParam param) {
try {
switch (action) {
case LOAD:
return connection.getUserlist(listId);
switch (param.mode) {
case ListActionParam.LOAD:
UserList result = connection.getUserlist(param.id);
return new ListActionResult(ListActionResult.LOAD, param.id, result, null);
case FOLLOW:
return connection.followUserlist(listId);
case ListActionParam.FOLLOW:
result = connection.followUserlist(param.id);
return new ListActionResult(ListActionResult.FOLLOW, param.id, result, null);
case UNFOLLOW:
return connection.unfollowUserlist(listId);
case ListActionParam.UNFOLLOW:
result = connection.unfollowUserlist(param.id);
return new ListActionResult(ListActionResult.UNFOLLOW, param.id, result, null);
case DELETE:
return connection.deleteUserlist(listId);
case ListActionParam.DELETE:
result = connection.deleteUserlist(param.id);
return new ListActionResult(ListActionResult.DELETE, param.id, result, null);
}
} catch (ConnectionException exception) {
this.exception = exception;
return new ListActionResult(ListActionResult.ERROR, param.id, null, exception);
} catch (Exception e) {
e.printStackTrace();
}
return null;
return new ListActionResult(ListActionResult.ERROR, param.id, null, null);
}
@Override
protected void onPostExecute(@Nullable UserList userList) {
UserlistActivity callback = this.weakRef.get();
if (callback != null) {
if (userList != null) {
callback.onSuccess(userList, action);
} else {
callback.onFailure(exception, listId);
}
public static class ListActionParam {
public static final int LOAD = 1;
public static final int FOLLOW = 2;
public static final int UNFOLLOW = 3;
public static final int DELETE = 4;
public final int mode;
public final long id;
public ListActionParam(int mode, long id) {
this.mode = mode;
this.id = id;
}
}
public static class ListActionResult {
public static final int LOAD = 5;
public static final int FOLLOW = 6;
public static final int UNFOLLOW = 7;
public static final int DELETE = 8;
public static final int ERROR = -1;
public final int mode;
public final long id;
@Nullable
public final UserList userlist;
@Nullable
public final ConnectionException exception;
ListActionResult(int mode, long id, @Nullable UserList userlist, @Nullable ConnectionException exception) {
this.userlist = userlist;
this.exception = exception;
this.mode = mode;
this.id = id;
}
}
}

View File

@ -1,16 +1,13 @@
package org.nuclearfog.twidda.backend.async;
import android.content.Context;
import android.os.AsyncTask;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.ui.activities.UserlistActivity;
import java.lang.ref.WeakReference;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
/**
* Backend async task to manage users on lists
@ -18,74 +15,72 @@ import java.lang.ref.WeakReference;
*
* @author nuclearfog
*/
public class ListManager extends AsyncTask<Void, Void, Boolean> {
/**
* add user to list
*/
public static final int ADD_USER = 1;
/**
* remove user from list
*/
public static final int DEL_USER = 2;
public class ListManager extends AsyncExecutor<ListManager.ListManagerParam, ListManager.ListManagerResult> {
private Connection connection;
private WeakReference<UserlistActivity> weakRef;
@Nullable
private ConnectionException exception;
private long listId;
private String username;
private int action;
/**
* @param c activity context
* @param listId ID of the user list
* @param action what action should be performed
* @param username name of the user to add or remove
* @param callback callback to update information
*
*/
public ListManager(Context c, long listId, int action, String username, UserlistActivity callback) {
super();
weakRef = new WeakReference<>(callback);
connection = ConnectionManager.get(c);
this.listId = listId;
this.action = action;
this.username = username;
public ListManager(Context context) {
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected Boolean doInBackground(Void... v) {
protected ListManagerResult doInBackground(ListManagerParam param) {
try {
switch (action) {
case ADD_USER:
connection.addUserToList(listId, username);
return true;
switch (param.mode) {
case ListManagerParam.ADD_USER:
connection.addUserToList(param.id, param.username);
return new ListManagerResult(ListManagerResult.ADD_USER, param.username, null);
case DEL_USER:
connection.removeUserFromList(listId, username);
return true;
case ListManagerParam.DEL_USER:
connection.removeUserFromList(param.id, param.username);
return new ListManagerResult(ListManagerResult.DEL_USER, param.username, null);
}
} catch (ConnectionException exception) {
this.exception = exception;
return new ListManagerResult(ListManagerResult.ERROR, param.username, exception);
} catch (Exception e) {
e.printStackTrace();
}
return false;
return new ListManagerResult(ListManagerResult.ERROR, param.username, null);
}
@Override
protected void onPostExecute(Boolean success) {
UserlistActivity callback = weakRef.get();
if (callback != null) {
if (success) {
callback.onSuccess(action, username);
} else {
callback.onFailure(exception);
}
public static class ListManagerParam {
public static final int ADD_USER = 1;
public static final int DEL_USER = 2;
public final long id;
public final String username;
public final int mode;
public ListManagerParam(int mode, long id, String username) {
this.id = id;
this.mode = mode;
this.username = username;
}
}
public static class ListManagerResult {
public static final int ERROR = -1;
public static final int ADD_USER = 3;
public static final int DEL_USER = 4;
public final int mode;
public final String name;
public final ConnectionException exception;
ListManagerResult(int mode, String name, ConnectionException exception) {
this.mode = mode;
this.name = name;
this.exception = exception;
}
}
}

View File

@ -1,69 +1,67 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.UserListUpdate;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.model.UserList;
import org.nuclearfog.twidda.ui.activities.UserlistEditor;
import java.lang.ref.WeakReference;
/**
* This class creates and updates user lists
* Backend for {@link UserlistEditor}
*
* @author nuclearfog
*/
public class ListUpdater extends AsyncTask<Void, Void, UserList> {
public class ListUpdater extends AsyncExecutor<UserListUpdate, ListUpdater.ListUpdateResult> {
private WeakReference<UserlistEditor> weakRef;
private Connection connection;
@Nullable
private ConnectionException exception;
private UserListUpdate update;
/**
* @param activity callback to {@link UserlistEditor}
* @param update userlist to update
*
*/
public ListUpdater(UserlistEditor activity, UserListUpdate update) {
super();
weakRef = new WeakReference<>(activity);
connection = ConnectionManager.get(activity);
this.update = update;
public ListUpdater(Context context) {
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected UserList doInBackground(Void... v) {
protected ListUpdateResult doInBackground(UserListUpdate update) {
try {
UserList result;
if (update.exists())
return connection.updateUserlist(update);
return connection.createUserlist(update);
result = connection.updateUserlist(update);
else
result = connection.createUserlist(update);
return new ListUpdateResult(result, update.exists(), null);
} catch (ConnectionException exception) {
this.exception = exception;
return new ListUpdateResult(null, update.exists(), exception);
} catch (Exception e) {
e.printStackTrace();
}
return null;
return new ListUpdateResult(null, update.exists(), null);
}
@Override
protected void onPostExecute(@Nullable UserList result) {
UserlistEditor activity = weakRef.get();
if (activity != null) {
if (result != null) {
activity.onSuccess(result, update.exists());
} else {
activity.onError(exception);
}
public static class ListUpdateResult {
public final boolean updated;
@Nullable
public final UserList userlist;
@Nullable
public final ConnectionException exception;
ListUpdateResult(@Nullable UserList userlist, boolean updated, @Nullable ConnectionException exception) {
this.userlist = userlist;
this.updated = updated;
this.exception = exception;
}
}
}

View File

@ -1,16 +1,17 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.ui.activities.SettingsActivity;
import java.lang.ref.WeakReference;
import java.util.List;
/**
@ -19,44 +20,41 @@ import java.util.List;
* @author nuclearfog
* @see SettingsActivity
*/
public class LocationLoader extends AsyncTask<Void, Void, List<Location>> {
public class LocationLoader extends AsyncExecutor<Void, LocationLoader.LocationLoaderResult> {
private WeakReference<SettingsActivity> weakRef;
private Connection connection;
@Nullable
private ConnectionException exception;
public LocationLoader(SettingsActivity activity) {
super();
weakRef = new WeakReference<>(activity);
connection = ConnectionManager.get(activity);
public LocationLoader(Context context) {
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected List<Location> doInBackground(Void... v) {
protected LocationLoaderResult doInBackground(Void v) {
try {
return connection.getLocations();
List<Location> locations = connection.getLocations();
return new LocationLoaderResult(locations, null);
} catch (ConnectionException exception) {
this.exception = exception;
return new LocationLoaderResult(null, exception);
} catch (Exception e) {
e.printStackTrace();
}
return null;
return new LocationLoaderResult(null, null);
}
@Override
protected void onPostExecute(@Nullable List<Location> locations) {
SettingsActivity activity = weakRef.get();
if (activity != null) {
if (locations != null) {
activity.setLocationData(locations);
} else {
activity.onError(exception);
}
public static class LocationLoaderResult {
@Nullable
public final List<Location> locations;
@Nullable
public final ConnectionException exception;
public LocationLoaderResult(@Nullable List<Location> locations, @Nullable ConnectionException exception) {
this.locations = locations;
this.exception = exception;
}
}
}

View File

@ -1,17 +1,18 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.Messages;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.ui.fragments.MessageFragment;
import java.lang.ref.WeakReference;
/**
* task to download a direct message list from twitter and handle message actions
@ -19,112 +20,95 @@ import java.lang.ref.WeakReference;
* @author nuclearfog
* @see MessageFragment
*/
public class MessageLoader extends AsyncTask<Void, Void, Messages> {
public class MessageLoader extends AsyncExecutor<MessageLoader.MessageLoaderParam, MessageLoader.MessageLoaderResult> {
/**
* load messages from database
*/
public static final int DB = 1;
/**
* load messages online
*/
public static final int LOAD = 2;
/**
* delete message
*/
public static final int DEL = 3;
private WeakReference<MessageFragment> weakRef;
private Connection connection;
private AppDatabase db;
private int action;
@Nullable
private ConnectionException exception;
private String cursor;
private long messageId;
/**
* @param fragment Callback to update data
* @param action what action should be performed
* @param cursor list cursor provided by twitter
* @param messageId if {@link #DEL} is selected this ID is used to delete the message
*
*/
public MessageLoader(MessageFragment fragment, int action, String cursor, long messageId) {
super();
weakRef = new WeakReference<>(fragment);
db = new AppDatabase(fragment.getContext());
connection = ConnectionManager.get(fragment.getContext());
this.action = action;
this.cursor = cursor;
this.messageId = messageId;
public MessageLoader(Context context) {
db = new AppDatabase(context);
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected Messages doInBackground(Void... v) {
Messages messages = null;
protected MessageLoaderResult doInBackground(MessageLoaderParam param) {
try {
switch (action) {
case DB:
messages = db.getMessages();
switch (param.mode) {
case MessageLoaderParam.DATABASE:
Messages messages = db.getMessages();
if (messages.isEmpty()) {
messages = connection.getDirectmessages("");
// merge online messages with offline messages
db.saveMessages(messages);
messages = db.getMessages();
}
return messages;
return new MessageLoaderResult(MessageLoaderResult.DATABASE, param.id, messages, null);
case LOAD:
messages = connection.getDirectmessages(cursor);
case MessageLoaderParam.ONLINE:
messages = connection.getDirectmessages(param.cursor);
// merge online messages with offline messages
db.saveMessages(messages);
return db.getMessages();
messages = db.getMessages();
return new MessageLoaderResult(MessageLoaderResult.ONLINE, param.id, messages, null);
case DEL:
connection.deleteDirectmessage(messageId);
db.removeMessage(messageId);
break;
case MessageLoaderParam.DELETE:
connection.deleteDirectmessage(param.id);
db.removeMessage(param.id);
return new MessageLoaderResult(MessageLoaderResult.DELETE, param.id, null, null);
}
} catch (ConnectionException exception) {
this.exception = exception;
if (exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
db.removeMessage(messageId);
}
if (exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND)
db.removeMessage(param.id);
return new MessageLoaderResult(MessageLoaderResult.ERROR, param.id, null, exception);
} catch (Exception e) {
e.printStackTrace();
messageId = -1L; // remove ID of the message
}
return messages;
return new MessageLoaderResult(MessageLoaderResult.ERROR, param.id, null, null);
}
@Override
protected void onPostExecute(@Nullable Messages messages) {
MessageFragment fragment = weakRef.get();
if (fragment != null) {
switch (action) {
case DB:
case LOAD:
if (messages != null) {
fragment.setData(messages);
}
if (messages == null || exception != null) {
fragment.onError(exception, messageId);
}
break;
public static class MessageLoaderParam {
case DEL:
if (exception != null || messageId != -1L) {
fragment.onError(exception, messageId);
} else {
fragment.removeItem(messageId);
}
break;
}
public static final int DATABASE = 1;
public static final int ONLINE = 2;
public static final int DELETE = 3;
public final int mode;
public final long id;
public final String cursor;
public MessageLoaderParam(int mode, long id, String cursor) {
this.mode = mode;
this.id = id;
this.cursor = cursor;
}
}
public static class MessageLoaderResult {
public static final int ERROR = -1;
public static final int DATABASE = 4;
public static final int ONLINE = 5;
public static final int DELETE = 6;
public final int mode;
public final long id;
@Nullable
public final Messages messages;
@Nullable
public final ConnectionException exception;
MessageLoaderResult(int mode, long id, @Nullable Messages messages, @Nullable ConnectionException exception) {
this.mode = mode;
this.id = id;
this.messages = messages;
this.exception = exception;
}
}
}

View File

@ -1,82 +1,69 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.MessageUpdate;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.ui.activities.MessageEditor;
import java.lang.ref.WeakReference;
/**
* Background task to send a direct messages to a user
*
* @author nuclearfog
* @see MessageEditor
*/
public class MessageUpdater extends AsyncTask<Void, Void, Boolean> {
public class MessageUpdater extends AsyncExecutor<MessageUpdate, MessageUpdater.MessageUpdateResult> {
private WeakReference<MessageEditor> weakRef;
private Connection connection;
@Nullable
private ConnectionException exception;
private MessageUpdate message;
/**
* send direct message
*
* @param activity Activity context
*/
public MessageUpdater(@NonNull MessageEditor activity, MessageUpdate message) {
super();
connection = ConnectionManager.get(activity);
weakRef = new WeakReference<>(activity);
this.message = message;
public MessageUpdater(Context context) {
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected Boolean doInBackground(Void... v) {
protected MessageUpdateResult doInBackground(MessageUpdate update) {
try {
// first check if user exists
long id = connection.showUser(message.getReceiver()).getId();
long id = connection.showUser(update.getReceiver()).getId();
// upload media if any
long mediaId = -1;
if (message.getMediaUpdate() != null) {
mediaId = connection.uploadMedia(message.getMediaUpdate());
if (update.getMediaUpdate() != null) {
mediaId = connection.uploadMedia(update.getMediaUpdate());
}
// upload message and media ID
if (!isCancelled()) {
connection.sendDirectmessage(id, message.getMessage(), mediaId);
connection.sendDirectmessage(id, update.getMessage(), mediaId);
}
return true;
return new MessageUpdateResult(true, null);
} catch (ConnectionException exception) {
this.exception = exception;
return new MessageUpdateResult(false, exception);
} catch (Exception e) {
e.printStackTrace();
} finally {
// close all streams
message.close();
update.close();
}
return false;
return new MessageUpdateResult(false, null);
}
@Override
protected void onPostExecute(Boolean success) {
MessageEditor activity = weakRef.get();
if (activity != null) {
if (success) {
activity.onSuccess();
} else {
activity.onError(exception);
}
public static class MessageUpdateResult {
public final boolean success;
public final ConnectionException exception;
public MessageUpdateResult(boolean success, ConnectionException exception) {
this.exception = exception;
this.success = success;
}
}
}

View File

@ -0,0 +1,138 @@
package org.nuclearfog.twidda.backend.async;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.Relation;
import org.nuclearfog.twidda.ui.activities.ProfileActivity;
/**
* This background task loads profile information about a twitter user and take actions
*
* @author nuclearfog
* @see ProfileActivity
*/
public class RelationLoader extends AsyncExecutor<RelationLoader.RelationParam, RelationLoader.RelationResult> {
private Connection connection;
private AppDatabase db;
/**
*
*/
public RelationLoader(Context context) {
connection = ConnectionManager.get(context);
db = new AppDatabase(context);
}
@NonNull
@Override
protected RelationResult doInBackground(RelationParam param) {
try {
switch (param.mode) {
case RelationParam.LOAD:
Relation relation = connection.getUserRelationship(param.id);
return new RelationResult(RelationResult.LOAD, relation);
case RelationParam.FOLLOW:
relation = connection.followUser(param.id);
return new RelationResult(RelationResult.FOLLOW, relation);
case RelationParam.UNFOLLOW:
relation = connection.unfollowUser(param.id);
return new RelationResult(RelationResult.UNFOLLOW, relation);
case RelationParam.BLOCK:
relation = connection.blockUser(param.id);
db.muteUser(param.id, true);
db.addUserToFilterlist(param.id);
return new RelationResult(RelationResult.BLOCK, relation);
case RelationParam.UNBLOCK:
relation = connection.unblockUser(param.id);
// remove from exclude list only if user is not muted
if (!relation.isMuted()) {
db.muteUser(param.id, false);
db.removeUserFromFilterlist(param.id);
}
return new RelationResult(RelationResult.UNBLOCK, relation);
case RelationParam.MUTE:
relation = connection.muteUser(param.id);
db.muteUser(param.id, true);
return new RelationResult(RelationResult.MUTE, relation);
case RelationParam.UNMUTE:
relation = connection.unmuteUser(param.id);
// remove from exclude list only if user is not blocked
if (!relation.isBlocked()) {
db.muteUser(param.id, false);
db.removeUserFromFilterlist(param.id);
}
return new RelationResult(RelationResult.UNMUTE, relation);
}
} catch (ConnectionException exception) {
return new RelationResult(RelationResult.ERROR, null, exception);
} catch (Exception e) {
e.printStackTrace();
}
return new RelationResult(RelationResult.ERROR, null, null);
}
public static class RelationParam {
public static final int LOAD = 1;
public static final int FOLLOW = 2;
public static final int UNFOLLOW = 3;
public static final int BLOCK = 4;
public static final int UNBLOCK = 5;
public static final int MUTE = 6;
public static final int UNMUTE = 7;
public final long id;
public final int mode;
public RelationParam(long id, int mode) {
this.id = id;
this.mode = mode;
}
}
public static class RelationResult {
public static final int LOAD = 8;
public static final int FOLLOW = 9;
public static final int UNFOLLOW = 10;
public static final int BLOCK = 11;
public static final int UNBLOCK = 12;
public static final int MUTE = 13;
public static final int UNMUTE = 14;
public static final int ERROR = -1;
public final int mode;
@Nullable
public final Relation relation;
@Nullable
public final ConnectionException exception;
RelationResult(int mode, Relation relation) {
this(mode, relation, null);
}
RelationResult(int mode, @Nullable Relation relation, @Nullable ConnectionException exception) {
this.relation = relation;
this.exception = exception;
this.mode = mode;
}
}
}

View File

@ -1,219 +1,168 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import android.content.Context;
import androidx.annotation.Nullable;
import androidx.annotation.NonNull;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.Status;
import org.nuclearfog.twidda.ui.activities.StatusActivity;
import java.lang.ref.WeakReference;
/**
* Background task to download a status informations and to take actions
*
* @author nuclearfog
* @see StatusActivity
*/
public class StatusAction extends AsyncTask<Long, Status, Boolean> {
/**
* Load status
*/
public static final int LOAD_ONLINE = 1;
/**
* load status from database first
*/
public static final int LOAD_DATABASE = 2;
/**
* repsot status
*/
public static final int REPOST = 3;
/**
* remove repost
* (delete operation, "status ID" required)
*/
public static final int REMOVE_REPOST = 4;
/**
* favorite status
*/
public static final int FAVORITE = 5;
/**
* remove status from favorites
*/
public static final int UNFAVORITE = 6;
/**
* hide reply
*/
public static final int HIDE = 7;
/**
* unhide reply
*/
public static final int UNHIDE = 8;
/**
* bookmark status
*/
public static final int BOOKMARK = 9;
/**
* remove bookmark from status
*/
public static final int UNBOOKMARK = 10;
/**
* delete status
* (delete operation, "status ID" required)
*/
public static final int DELETE = 20;
public class StatusAction extends AsyncExecutor<StatusAction.StatusParam, StatusAction.StatusResult> {
private Connection connection;
private WeakReference<StatusActivity> weakRef;
private AppDatabase db;
@Nullable
private ConnectionException exception;
private int action;
/**
* @param action action for a given status
*
*/
public StatusAction(StatusActivity activity, int action) {
super();
weakRef = new WeakReference<>(activity);
connection = ConnectionManager.get(activity);
db = new AppDatabase(activity);
this.action = action;
public StatusAction(Context context) {
connection = ConnectionManager.get(context);
db = new AppDatabase(context);
}
/**
* @param ids first value is the status ID. The second value is the repost status ID. Required for delete operations
*/
@NonNull
@Override
protected Boolean doInBackground(Long... ids) {
org.nuclearfog.twidda.model.Status status;
protected StatusResult doInBackground(StatusParam param) {
try {
switch (action) {
case LOAD_DATABASE:
status = db.getStatus(ids[0]);
switch (param.mode) {
case StatusParam.DATABASE:
Status status = db.getStatus(param.id);
if (status != null) {
publishProgress(status);
return new StatusResult(StatusResult.DATABASE, status);
}
// fall through
case LOAD_ONLINE:
status = connection.showStatus(ids[0]);
publishProgress(status);
if (db.containsStatus(ids[0])) {
case StatusParam.ONLINE:
status = connection.showStatus(param.id);
if (db.containsStatus(param.id)) {
// update status if there is a database entry
db.updateStatus(status);
}
return true;
return new StatusResult(StatusResult.ONLINE, status);
case DELETE:
connection.deleteStatus(ids[0]);
db.removeStatus(ids[0]);
// removing repost reference to this status
db.removeStatus(ids[1]);
return true;
case StatusParam.DELETE:
connection.deleteStatus(param.id);
db.removeStatus(param.id);
return new StatusResult(StatusResult.DELETE, null);
case REPOST:
status = connection.repostStatus(ids[0]);
case StatusParam.REPOST:
status = connection.repostStatus(param.id);
db.updateStatus(status);
if (status.getEmbeddedStatus() != null)
publishProgress(status.getEmbeddedStatus());
db.updateStatus(status);
return true;
return new StatusResult(StatusResult.REPOST, status.getEmbeddedStatus());
return new StatusResult(StatusResult.REPOST, status);
case REMOVE_REPOST:
status = connection.removeRepost(ids[0]);
publishProgress(status);
case StatusParam.UNREPOST:
status = connection.removeRepost(param.id);
db.updateStatus(status);
// removing repost reference to this status
if (ids.length == 2)
db.removeStatus(ids[1]);
return true;
return new StatusResult(StatusResult.UNREPOST, status);
case FAVORITE:
status = connection.favoriteStatus(ids[0]);
publishProgress(status);
case StatusParam.FAVORITE:
status = connection.favoriteStatus(param.id);
db.addToFavorits(status);
return true;
return new StatusResult(StatusResult.FAVORITE, status);
case UNFAVORITE:
status = connection.unfavoriteStatus(ids[0]);
publishProgress(status);
case StatusParam.UNFAVORITE:
status = connection.unfavoriteStatus(param.id);
db.removeFromFavorite(status);
return true;
return new StatusResult(StatusResult.UNFAVORITE, status);
case BOOKMARK:
status = connection.bookmarkStatus(ids[0]);
publishProgress(status);
case StatusParam.BOOKMARK:
status = connection.bookmarkStatus(param.id);
db.addToBookmarks(status);
return true;
return new StatusResult(StatusResult.BOOKMARK, status);
case UNBOOKMARK:
status = connection.removeBookmark(ids[0]);
publishProgress(status);
case StatusParam.UNBOOKMARK:
status = connection.removeBookmark(param.id);
db.removeFromBookmarks(status);
return true;
return new StatusResult(StatusResult.UNBOOKMARK, status);
case HIDE:
connection.muteConversation(ids[0]);
db.hideStatus(ids[0], true);
return true;
case StatusParam.HIDE:
connection.muteConversation(param.id);
db.hideStatus(param.id, true);
return new StatusResult(StatusResult.HIDE, null);
case UNHIDE:
connection.unmuteConversation(ids[0]);
db.hideStatus(ids[0], false);
return true;
case StatusParam.UNHIDE:
connection.unmuteConversation(param.id);
db.hideStatus(param.id, false);
return new StatusResult(StatusResult.UNHIDE, null);
}
} catch (ConnectionException exception) {
this.exception = exception;
if (exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
// delete database entry if status was not found
db.removeStatus(ids[0]);
if (ids.length > 1) {
// also remove reference to this status
db.removeStatus(ids[1]);
}
db.removeStatus(param.id);
}
return new StatusResult(StatusResult.ERROR, null, exception);
} catch (Exception e) {
e.printStackTrace();
}
return false;
return new StatusResult(StatusResult.ERROR, null, null);
}
@Override
protected void onProgressUpdate(org.nuclearfog.twidda.model.Status... statuses) {
StatusActivity activity = weakRef.get();
if (activity != null && statuses.length > 0 && statuses[0] != null) {
activity.setStatus(statuses[0]);
public static class StatusParam {
public static final int ONLINE = 1;
public static final int DATABASE = 2;
public static final int REPOST = 3;
public static final int UNREPOST = 4;
public static final int FAVORITE = 5;
public static final int UNFAVORITE = 6;
public static final int HIDE = 7;
public static final int UNHIDE = 8;
public static final int BOOKMARK = 9;
public static final int UNBOOKMARK = 10;
public static final int DELETE = 11;
public final int mode;
public final long id;
public StatusParam(int mode, long id) {
this.mode = mode;
this.id = id;
}
}
@Override
protected void onPostExecute(Boolean success) {
StatusActivity activity = weakRef.get();
if (activity != null) {
if (success) {
activity.OnSuccess(action);
} else {
activity.onError(exception);
}
public static class StatusResult {
public static final int ERROR = -1;
public static final int ONLINE = 12;
public static final int DATABASE = 13;
public static final int REPOST = 14;
public static final int UNREPOST = 15;
public static final int FAVORITE = 16;
public static final int UNFAVORITE = 17;
public static final int HIDE = 18;
public static final int UNHIDE = 19;
public static final int BOOKMARK = 20;
public static final int UNBOOKMARK = 21;
public static final int DELETE = 22;
public final int mode;
public final Status status;
public final ConnectionException exception;
StatusResult(int mode, Status status) {
this(mode, status, null);
}
StatusResult(int mode, Status status, ConnectionException exception) {
this.mode = mode;
this.status = status;
this.exception = exception;
}
}
}

View File

@ -1,46 +1,40 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import android.content.Context;
import androidx.annotation.NonNull;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.helper.MediaStatus;
import org.nuclearfog.twidda.backend.helper.StatusUpdate;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.ui.activities.StatusEditor;
import java.lang.ref.WeakReference;
/**
* Background task for posting a status
*
* @author nuclearfog
* @see StatusEditor
*/
public class StatusUpdater extends AsyncTask<StatusUpdate, Void, Boolean> {
public class StatusUpdater extends AsyncExecutor<StatusUpdate, StatusUpdater.StatusUpdateResult> {
private Connection connection;
private ConnectionException exception;
private WeakReference<StatusEditor> weakRef;
/**
* initialize task
*
* @param activity Activity context
*/
public StatusUpdater(StatusEditor activity) {
super();
connection = ConnectionManager.get(activity);
weakRef = new WeakReference<>(activity);
public StatusUpdater(Context context) {
connection = ConnectionManager.get(context);
}
@NonNull
@Override
protected Boolean doInBackground(StatusUpdate... statusUpdates) {
StatusUpdate statusUpdate = statusUpdates[0];
protected StatusUpdateResult doInBackground(StatusUpdate update) {
try {
// upload media first
MediaStatus[] mediaUpdates = statusUpdate.getMediaUpdates();
MediaStatus[] mediaUpdates = update.getMediaUpdates();
long[] mediaIds = new long[mediaUpdates.length];
for (int pos = 0; pos < mediaUpdates.length; pos++) {
// upload media file and save media ID
@ -48,30 +42,28 @@ public class StatusUpdater extends AsyncTask<StatusUpdate, Void, Boolean> {
}
// upload status
if (!isCancelled()) {
connection.uploadStatus(statusUpdate, mediaIds);
connection.uploadStatus(update, mediaIds);
}
return true;
return new StatusUpdateResult(true, null);
} catch (ConnectionException exception) {
this.exception = exception;
return new StatusUpdateResult(false, exception);
} catch (Exception e) {
e.printStackTrace();
} finally {
// close inputstreams
statusUpdate.close();
update.close();
}
return false;
return new StatusUpdateResult(false, null);
}
@Override
protected void onPostExecute(Boolean success) {
StatusEditor activity = weakRef.get();
if (activity != null) {
if (success) {
activity.onSuccess();
} else {
activity.onError(exception);
}
public static class StatusUpdateResult {
public final boolean success;
public final ConnectionException exception;
StatusUpdateResult(boolean success, ConnectionException exception) {
this.success = success;
this.exception = exception;
}
}
}

View File

@ -1,181 +0,0 @@
package org.nuclearfog.twidda.backend.async;
import android.os.AsyncTask;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.Relation;
import org.nuclearfog.twidda.model.User;
import org.nuclearfog.twidda.ui.activities.ProfileActivity;
import java.lang.ref.WeakReference;
/**
* This background task loads profile information about a twitter user and take actions
*
* @author nuclearfog
* @see ProfileActivity
*/
public class UserAction extends AsyncTask<Void, User, Relation> {
/**
* Load profile information
*/
public static final int PROFILE_lOAD = 1;
/**
* load profile from database first
*/
public static final int PROFILE_DB = 2;
/**
* follow user
*/
public static final int ACTION_FOLLOW = 3;
/**
* un-follow user
*/
public static final int ACTION_UNFOLLOW = 4;
/**
* block user
*/
public static final int ACTION_BLOCK = 5;
/**
* un-block user
*/
public static final int ACTION_UNBLOCK = 6;
/**
* mute user
*/
public static final int ACTION_MUTE = 7;
/**
* un-mute user
*/
public static final int ACTION_UNMUTE = 8;
private ConnectionException error;
private WeakReference<ProfileActivity> weakRef;
private Connection connection;
private AppDatabase db;
private long userId;
private int action;
/**
* @param activity Callback to return the result
* @param userId ID of the twitter user
*/
public UserAction(ProfileActivity activity, int action, long userId) {
super();
connection = ConnectionManager.get(activity);
db = new AppDatabase(activity);
this.weakRef = new WeakReference<>(activity);
this.userId = userId;
this.action = action;
}
@Override
protected Relation doInBackground(Void... v) {
try {
switch (action) {
case PROFILE_DB:
// load user information from database
User user;
if (userId > 0) {
user = db.getUser(userId);
publishProgress(user);
}
case PROFILE_lOAD:
// load user information from twitter
user = connection.showUser(userId);
publishProgress(user);
db.saveUser(user);
// load user relations from twitter
Relation relation = connection.getUserRelationship(userId);
if (!relation.isCurrentUser()) {
boolean muteUser = relation.isBlocked() || relation.isMuted();
db.muteUser(userId, muteUser);
}
return relation;
case ACTION_FOLLOW:
connection.followUser(userId);
break;
case ACTION_UNFOLLOW:
connection.unfollowUser(userId);
break;
case ACTION_BLOCK:
connection.blockUser(userId);
db.muteUser(userId, true);
db.addUserToFilterlist(userId);
break;
case ACTION_UNBLOCK:
connection.unblockUser(userId);
// remove from exclude list only if user is not muted
relation = connection.getUserRelationship(userId);
if (!relation.isMuted()) {
db.muteUser(userId, false);
db.removeUserFromFilterlist(userId);
}
return relation;
case ACTION_MUTE:
connection.muteUser(userId);
db.muteUser(userId, true);
break;
case ACTION_UNMUTE:
connection.unmuteUser(userId);
// remove from exclude list only if user is not blocked
relation = connection.getUserRelationship(userId);
if (!relation.isBlocked()) {
db.muteUser(userId, false);
db.removeUserFromFilterlist(userId);
}
return relation;
}
return connection.getUserRelationship(userId);
} catch (ConnectionException exception) {
this.error = exception;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(User[] users) {
ProfileActivity activity = weakRef.get();
if (activity != null && users[0] != null) {
activity.setUser(users[0]);
}
}
@Override
protected void onPostExecute(@Nullable Relation relation) {
ProfileActivity activity = weakRef.get();
if (activity != null) {
if (relation != null) {
activity.onAction(relation);
} else {
activity.onError(error);
}
}
}
}

View File

@ -0,0 +1,92 @@
package org.nuclearfog.twidda.backend.async;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.api.Connection;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.api.ConnectionManager;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor;
import org.nuclearfog.twidda.database.AppDatabase;
import org.nuclearfog.twidda.model.User;
/**
* Async class to load user information
*
* @author nuclearfog
*/
public class UserLoader extends AsyncExecutor<UserLoader.UserParam, UserLoader.UserResult> {
private Connection connection;
private AppDatabase db;
public UserLoader(Context context) {
connection = ConnectionManager.get(context);
db = new AppDatabase(context);
}
@NonNull
@Override
protected UserResult doInBackground(UserParam param) {
try {
switch(param.mode) {
case UserParam.DATABASE:
if (param.id > 0) {
User user = db.getUser(param.id);
return new UserResult(UserResult.DATABASE, user, null);
}
case UserParam.ONLINE:
// load user information from twitter
User user = connection.showUser(param.id);
db.saveUser(user);
return new UserResult(UserResult.ONLINE, user, null);
}
}catch (ConnectionException exception) {
return new UserResult(UserResult.ERROR, null, exception);
} catch (Exception e) {
e.printStackTrace();
}
return new UserResult(UserResult.ERROR, null, null);
}
public static class UserParam {
public static final int DATABASE = 1;
public static final int ONLINE = 2;
public final int mode;
public final long id;
public UserParam(int mode, long id) {
this.mode = mode;
this.id = id;
}
}
public static class UserResult {
public static final int ERROR = -1;
public static final int DATABASE = 3;
public static final int ONLINE = 4;
@Nullable
public final User user;
@Nullable
public final ConnectionException exception;
public final int mode;
UserResult(int mode, @Nullable User user, @Nullable ConnectionException exception) {
this.mode = mode;
this.user = user;
this.exception = exception;
}
}
}

View File

@ -8,49 +8,75 @@ import androidx.annotation.NonNull;
import java.lang.ref.WeakReference;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Executor for tasks running in the bnackground
*
* @param <Parameter>
* @param <Result>
* @author nuclearfog
*/
public abstract class AsyncExecutor<Parameter, Result> {
private ExecutorService singleExecutor = Executors.newSingleThreadExecutor();
private static final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor();
private Handler uiHandler = new Handler(Looper.getMainLooper());
private WeakReference<AsyncCallback<Result>> callback;
private AtomicInteger processCount = new AtomicInteger(0);
private AtomicBoolean idle = new AtomicBoolean(true);
private AtomicBoolean cancel = new AtomicBoolean(false);
/**
* start packground task
*
* @param parameter parameter to send to the background task
* @param callback result from the background task
*/
public final void execute(final Parameter parameter, AsyncCallback<Result> callback) {
this.callback = new WeakReference<>(callback);
singleExecutor.submit(new Runnable() {
EXECUTOR.submit(new Runnable() {
@Override
public void run() {
processCount.getAndIncrement();
idle.set(false);
Result result = doInBackground(parameter);
onPostExecute(result);
processCount.getAndDecrement();
idle.set(true);
}
});
}
public final void kill() {
singleExecutor.shutdown();
processCount.set(0);
/**
* stop running and scheduled tasks
*/
public final void cancel() {
cancel.set(true);
}
public final boolean idle() {
return processCount.get() == 0;
/**
* check if there aren't any active tasks
*
* @return true if there aren't any tasks
*/
public final boolean isIdle() {
return idle.get();
}
/**
* check if current instance's thread is cancelled
*
* @return true if the thread of the current instance is cancelled
*/
public boolean isCancelled() {
return cancel.get();
}
/**
* send result to main thread
*
* @param result result of the background task
*/
private void onPostExecute(final Result result) {
uiHandler.post(new Runnable() {
@Override
@ -64,12 +90,24 @@ public abstract class AsyncExecutor<Parameter, Result> {
}
/**
* This method is called in a background thread
*
* @param param parameter containing information for the background task
* @return result of the background task
*/
@NonNull
protected abstract Result doInBackground(Parameter request);
protected abstract Result doInBackground(Parameter param);
/**
* Callback used to send task result to main thread
*/
public interface AsyncCallback<Result> {
void onResult(Result res);
/**
*
* @param result result of the task
*/
void onResult(Result result);
}
}

View File

@ -30,9 +30,7 @@ public enum Configuration {
NONE(0);
private final int accountType;
private final boolean enableVote;
private final boolean userlistExtended;
private final boolean favoritsEnabled;
private final boolean searchFilterEnabled;
private final boolean profileLocationEnabled;
private final boolean profileUrlEnabled;
@ -51,8 +49,6 @@ public enum Configuration {
case Account.API_TWITTER_1:
case Account.API_TWITTER_2:
userlistExtended = true;
favoritsEnabled = true;
enableVote = false;
searchFilterEnabled = true;
profileLocationEnabled = true;
profileUrlEnabled = true;
@ -63,24 +59,9 @@ public enum Configuration {
maxVideos = 1;
break;
case Account.API_MASTODON:
enableVote = true;
userlistExtended = false;
favoritsEnabled = false;
searchFilterEnabled = false;
profileLocationEnabled = false;
profileUrlEnabled = false;
idBlocklistEnabled = false;
postLocationSupported = false;
maxImages = 4;
maxGifs = 1;
maxVideos = 1;
break;
default:
case Account.API_MASTODON:
userlistExtended = false;
favoritsEnabled = false;
enableVote = false;
searchFilterEnabled = false;
profileLocationEnabled = false;
profileUrlEnabled = false;
@ -100,13 +81,6 @@ public enum Configuration {
return accountType;
}
/**
* @return true if network supports voting
*/
public boolean voteEnabled() {
return enableVote;
}
/**
* @return true to show extra userlist information
*/
@ -114,13 +88,6 @@ public enum Configuration {
return userlistExtended;
}
/**
* @return true to enable favorite timeline for users
*/
public boolean favoritsEnabled() {
return favoritsEnabled;
}
/**
* @return true if search filter option is enabled
*/

View File

@ -10,9 +10,9 @@ import java.io.Serializable;
public interface Relation extends Serializable {
/**
* @return true if the relation points to the current user
* @return User ID
*/
boolean isCurrentUser();
long getId();
/**
* @return true if current user is following this user

View File

@ -95,8 +95,8 @@ public class ImageViewer extends MediaActivity implements AsyncCallback<ImageRes
@Override
protected void onDestroy() {
if (imageAsync != null && !imageAsync.idle()) {
imageAsync.kill();
if (imageAsync != null && !imageAsync.isIdle()) {
imageAsync.cancel();
clearCache();
}
super.onDestroy();
@ -134,14 +134,14 @@ public class ImageViewer extends MediaActivity implements AsyncCallback<ImageRes
@Override
public void onResult(ImageResult res) {
if (res.uri != null) {
cacheUri = res.uri;
public void onResult(ImageResult result) {
if (result.uri != null) {
cacheUri = result.uri;
zoomImage.reset();
zoomImage.setImageURI(cacheUri);
loadingCircle.setVisibility(INVISIBLE);
} else {
String message = ErrorHandler.getErrorMessage(this, res.exception);
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
finish();
}

View File

@ -136,8 +136,8 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
@Override
protected void onDestroy() {
if (loginAsync != null && !loginAsync.idle())
loginAsync.kill();
if (loginAsync != null && !loginAsync.isIdle())
loginAsync.cancel();
super.onDestroy();
}
@ -184,7 +184,7 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
@Override
public void onClick(View v) {
if (loginAsync != null && !loginAsync.idle()) {
if (loginAsync != null && !loginAsync.isIdle()) {
return;
}
// get login request token
@ -275,20 +275,20 @@ public class LoginActivity extends AppCompatActivity implements ActivityResultCa
@Override
public void onResult(LoginResult res) {
switch (res.mode) {
public void onResult(LoginResult result) {
switch (result.mode) {
case LoginResult.MODE_LOGIN:
setResult(RETURN_LOGIN_SUCCESSFUL);
finish();
break;
case LoginResult.MODE_REQUEST:
loginLink = res.redirectUrl;
loginLink = result.redirectUrl;
connect();
break;
case LoginResult.MODE_ERROR:
String message = ErrorHandler.getErrorMessage(this, res.exception);
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
break;
}

View File

@ -30,10 +30,11 @@ import com.google.android.material.tabs.TabLayout.OnTabSelectedListener;
import com.google.android.material.tabs.TabLayout.Tab;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.config.Configuration;
import org.nuclearfog.twidda.ui.adapter.FragmentAdapter;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.LinkLoader;
import org.nuclearfog.twidda.backend.async.LinkLoader.LinkResult;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.config.GlobalSettings;
@ -44,7 +45,7 @@ import org.nuclearfog.twidda.ui.dialogs.ProgressDialog;
*
* @author nuclearfog
*/
public class MainActivity extends AppCompatActivity implements ActivityResultCallback<ActivityResult>, OnTabSelectedListener, OnQueryTextListener {
public class MainActivity extends AppCompatActivity implements ActivityResultCallback<ActivityResult>, OnTabSelectedListener, OnQueryTextListener, AsyncCallback<LinkResult> {
/**
* key used to set the tab page
@ -109,7 +110,7 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
// check if there is a Twitter link
if (getIntent().getData() != null) {
LinkLoader linkLoader = new LinkLoader(this);
linkLoader.execute(getIntent().getData());
linkLoader.execute(getIntent().getData(), this);
loadingCircle.show();
}
}
@ -261,34 +262,27 @@ public class MainActivity extends AppCompatActivity implements ActivityResultCal
adapter.scrollToTop(tab.getPosition());
}
/**
* called from {@link LinkLoader} when link information were successfully loaded
*
* @param holder holder with activity information and extras
*/
public void onSuccess(@NonNull LinkLoader.DataHolder holder) {
loadingCircle.dismiss();
if (holder.activity == MainActivity.class) {
int page = holder.data.getInt(KEY_TAB_PAGE, 0);
pager.setCurrentItem(page);
} else {
Intent intent = new Intent(this, holder.activity);
intent.putExtras(holder.data);
startActivity(intent);
}
}
/**
* called from {@link LinkLoader} when an error occurs
*/
public void onError(@Nullable ConnectionException exception) {
if (exception != null) {
String message = ErrorHandler.getErrorMessage(this, exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), R.string.error_open_link, Toast.LENGTH_SHORT).show();
}
@Override
public void onResult(LinkResult linkResult) {
loadingCircle.dismiss();
if (linkResult.data != null && linkResult.activity != null) {
if (linkResult.activity == MainActivity.class) {
int page = linkResult.data.getInt(KEY_TAB_PAGE, 0);
pager.setCurrentItem(page);
} else {
Intent intent = new Intent(this, linkResult.activity);
intent.putExtras(linkResult.data);
startActivity(intent);
}
} else {
if (linkResult.exception != null) {
String message = ErrorHandler.getErrorMessage(this, linkResult.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), R.string.error_open_link, Toast.LENGTH_SHORT).show();
}
}
}
/**

View File

@ -150,8 +150,8 @@ public abstract class MediaActivity extends AppCompatActivity implements Activit
locationManager.removeUpdates(this);
}
}
if (imageTask != null && !imageTask.idle()) {
imageTask.kill();
if (imageTask != null && !imageTask.isIdle()) {
imageTask.cancel();
}
super.onDestroy();
}
@ -233,7 +233,7 @@ public abstract class MediaActivity extends AppCompatActivity implements Activit
@SuppressWarnings("IOStreamConstructor")
private void saveImage() {
try {
if ((imageTask == null || imageTask.idle()) && destMediaFile != null && srcMediaUri != null) {
if ((imageTask == null || imageTask.isIdle()) && destMediaFile != null && srcMediaUri != null) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
// store images directly
InputStream src = getContentResolver().openInputStream(srcMediaUri);

View File

@ -1,6 +1,5 @@
package org.nuclearfog.twidda.ui.activities;
import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.GONE;
import static android.view.View.OnClickListener;
import static android.view.View.VISIBLE;
@ -22,10 +21,11 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.MessageUpdater;
import org.nuclearfog.twidda.backend.async.MessageUpdater.MessageUpdateResult;
import org.nuclearfog.twidda.backend.helper.MessageUpdate;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.ui.dialogs.ConfirmDialog;
import org.nuclearfog.twidda.ui.dialogs.ConfirmDialog.OnConfirmListener;
@ -37,7 +37,7 @@ import org.nuclearfog.twidda.ui.dialogs.ProgressDialog.OnProgressStopListener;
*
* @author nuclearfog
*/
public class MessageEditor extends MediaActivity implements OnClickListener, OnConfirmListener, OnProgressStopListener {
public class MessageEditor extends MediaActivity implements OnClickListener, OnConfirmListener, OnProgressStopListener, AsyncCallback<MessageUpdateResult> {
/**
* key for the screenname if any
@ -102,8 +102,8 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
@Override
protected void onDestroy() {
if (messageAsync != null && messageAsync.getStatus() == RUNNING)
messageAsync.cancel(true);
if (messageAsync != null && !messageAsync.isIdle())
messageAsync.cancel();
loadingCircle.dismiss();
if (holder != null) {
holder.close();
@ -134,7 +134,7 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
public void onClick(View v) {
// send direct message
if (v.getId() == R.id.popup_message_send) {
if (messageAsync == null || messageAsync.getStatus() != RUNNING) {
if (messageAsync == null || messageAsync.isIdle()) {
sendMessage();
}
}
@ -155,8 +155,8 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
@Override
public void stopProgress() {
if (messageAsync != null && messageAsync.getStatus() == RUNNING) {
messageAsync.cancel(true);
if (messageAsync != null && !messageAsync.isIdle()) {
messageAsync.cancel();
}
}
@ -173,23 +173,17 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
}
}
/**
* called when direct message is sent
*/
public void onSuccess() {
Toast.makeText(getApplicationContext(), R.string.info_dm_send, Toast.LENGTH_SHORT).show();
finish();
}
/**
* called when an error occurs
*
* @param exception Engine Exception
*/
public void onError(@Nullable ConnectionException exception) {
String message = ErrorHandler.getErrorMessage(this, exception);
confirmDialog.show(ConfirmDialog.MESSAGE_EDITOR_ERROR, message);
loadingCircle.dismiss();
@Override
public void onResult(MessageUpdateResult result) {
if (result.success) {
Toast.makeText(getApplicationContext(), R.string.info_dm_send, Toast.LENGTH_SHORT).show();
finish();
} else {
String message = ErrorHandler.getErrorMessage(this, result.exception);
confirmDialog.show(ConfirmDialog.MESSAGE_EDITOR_ERROR, message);
loadingCircle.dismiss();
}
}
/**
@ -202,8 +196,8 @@ public class MessageEditor extends MediaActivity implements OnClickListener, OnC
if (holder.prepare(getContentResolver())) {
holder.setReceiver(username);
holder.setText(message);
messageAsync = new MessageUpdater(this, holder);
messageAsync.execute();
messageAsync = new MessageUpdater(this);
messageAsync.execute(holder, this);
loadingCircle.show();
} else {
Toast.makeText(getApplicationContext(), R.string.error_media_init, LENGTH_SHORT).show();

View File

@ -1,7 +1,6 @@
package org.nuclearfog.twidda.ui.activities;
import static android.content.Intent.ACTION_VIEW;
import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.GONE;
import static android.view.View.OnClickListener;
import static android.view.View.VISIBLE;
@ -60,9 +59,14 @@ import org.nuclearfog.tag.Tagger;
import org.nuclearfog.tag.Tagger.OnTagClickListener;
import org.nuclearfog.textviewtool.LinkAndScrollMovement;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.async.UserLoader;
import org.nuclearfog.twidda.backend.async.UserLoader.UserParam;
import org.nuclearfog.twidda.backend.async.UserLoader.UserResult;
import org.nuclearfog.twidda.ui.adapter.FragmentAdapter;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.UserAction;
import org.nuclearfog.twidda.backend.async.RelationLoader;
import org.nuclearfog.twidda.backend.async.RelationLoader.RelationParam;
import org.nuclearfog.twidda.backend.async.RelationLoader.RelationResult;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.backend.utils.PicassoBuilder;
@ -104,12 +108,6 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
*/
private static final String KEY_PROFILE_RELATION = "profile_relation";
/**
* key to prevent this activity to reload profile information as they are up to date
* value type is Boolean
*/
public static final String KEY_PROFILE_DISABLE_RELOAD = "profile_no_reload";
/**
* key to send updated user data
* value type is {@link User}
@ -135,9 +133,7 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
private FragmentAdapter adapter;
private GlobalSettings settings;
private UserAction profileAsync;
private Picasso picasso;
private ConfirmDialog confirmDialog;
private NestedScrollView root;
@ -151,10 +147,15 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
private TabLayout tabLayout;
private Toolbar toolbar;
@Nullable
private RelationLoader relationLoader;
@Nullable
private UserLoader userLoader;
@Nullable
private Relation relation;
@Nullable
private User user;
private long userId;
@Override
@ -221,9 +222,10 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
Object o = i.getSerializableExtra(KEY_PROFILE_USER);
if (o instanceof User) {
user = (User) o;
userId = user.getId();
adapter.setupProfilePage(user.getId());
} else {
long userId = i.getLongExtra(KEY_PROFILE_ID, 0);
userId = i.getLongExtra(KEY_PROFILE_ID, 0);
adapter.setupProfilePage(userId);
}
if (settings.likeEnabled()) {
@ -245,19 +247,21 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
@Override
protected void onStart() {
super.onStart();
if (profileAsync == null) {
Intent data = getIntent();
if (userLoader == null) {
UserParam param;
userLoader = new UserLoader(this);
if (user == null) {
long userId = data.getLongExtra(KEY_PROFILE_ID, 0);
profileAsync = new UserAction(this, UserAction.PROFILE_DB, userId);
profileAsync.execute();
} else if (relation == null) {
param = new UserParam(UserParam.DATABASE, userId);
} else {
param = new UserParam(UserParam.ONLINE, userId);
setUser(user);
if (!data.getBooleanExtra(KEY_PROFILE_DISABLE_RELOAD, false)) {
profileAsync = new UserAction(this, UserAction.PROFILE_lOAD, user.getId());
profileAsync.execute();
}
}
userLoader.execute(param, this::setUserResult);
}
if (relationLoader == null && userId != settings.getLogin().getId()) {
relationLoader = new RelationLoader(this);
RelationParam param = new RelationParam(userId, RelationParam.LOAD);
relationLoader.execute(param, this::setRelationResult);
}
}
@ -284,8 +288,8 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
@Override
protected void onDestroy() {
if (profileAsync != null && profileAsync.getStatus() == RUNNING)
profileAsync.cancel(true);
if (relationLoader != null && !relationLoader.isIdle())
relationLoader.cancel();
super.onDestroy();
}
@ -405,9 +409,10 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
// follow / unfollow user
else if (item.getItemId() == R.id.profile_follow) {
if (relation != null && user != null) {
if (!relation.isFollowing() && (profileAsync == null || profileAsync.getStatus() != RUNNING)) {
profileAsync = new UserAction(this, UserAction.ACTION_FOLLOW, user.getId());
profileAsync.execute();
if (!relation.isFollowing() && (relationLoader == null || relationLoader.isIdle())) {
RelationParam param = new RelationParam(user.getId(), RelationParam.FOLLOW);
relationLoader = new RelationLoader(this);
relationLoader.execute(param, this::setRelationResult);
} else {
confirmDialog.show(ConfirmDialog.PROFILE_UNFOLLOW);
}
@ -416,9 +421,10 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
// mute user
else if (item.getItemId() == R.id.profile_mute) {
if (relation != null && user != null) {
if (relation.isMuted() && (profileAsync == null || profileAsync.getStatus() != RUNNING)) {
profileAsync = new UserAction(this, UserAction.ACTION_UNMUTE, user.getId());
profileAsync.execute();
if (relation.isMuted() && (relationLoader == null || relationLoader.isIdle())) {
RelationParam param = new RelationParam(user.getId(), RelationParam.UNMUTE);
relationLoader = new RelationLoader(this);
relationLoader.execute(param, this::setRelationResult);
} else {
confirmDialog.show(ConfirmDialog.PROFILE_MUTE);
}
@ -427,9 +433,10 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
// block user
else if (item.getItemId() == R.id.profile_block) {
if (relation != null && user != null) {
if (relation.isBlocked() && (profileAsync == null || profileAsync.getStatus() != RUNNING)) {
profileAsync = new UserAction(this, UserAction.ACTION_UNBLOCK, user.getId());
profileAsync.execute();
if (relation.isBlocked() && (relationLoader == null || relationLoader.isIdle())) {
RelationParam param = new RelationParam(user.getId(), RelationParam.UNBLOCK);
relationLoader = new RelationLoader(this);
relationLoader.execute(param, this::setRelationResult);
} else {
confirmDialog.show(ConfirmDialog.PROFILE_BLOCK);
}
@ -587,18 +594,21 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
return;
// confirmed unfollowing user
if (type == ConfirmDialog.PROFILE_UNFOLLOW) {
profileAsync = new UserAction(this, UserAction.ACTION_UNFOLLOW, user.getId());
profileAsync.execute();
RelationParam param = new RelationParam(user.getId(), RelationParam.UNFOLLOW);
relationLoader = new RelationLoader(this);
relationLoader.execute(param, this::setRelationResult);
}
// confirmed blocking user
else if (type == ConfirmDialog.PROFILE_BLOCK) {
profileAsync = new UserAction(this, UserAction.ACTION_BLOCK, user.getId());
profileAsync.execute();
RelationParam param = new RelationParam(user.getId(), RelationParam.BLOCK);
relationLoader = new RelationLoader(this);
relationLoader.execute(param, this::setRelationResult);
}
// confirmed muting user
else if (type == ConfirmDialog.PROFILE_MUTE) {
profileAsync = new UserAction(this, UserAction.ACTION_MUTE, user.getId());
profileAsync.execute();
RelationParam param = new RelationParam(user.getId(), RelationParam.MUTE);
relationLoader = new RelationLoader(this);
relationLoader.execute(param, this::setRelationResult);
}
}
@ -643,13 +653,85 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
public void onError(Exception e) {
}
/**
* set user result information
*
* @param result user result from async executor
*/
private void setUserResult(UserResult result) {
switch(result.mode) {
case UserResult.DATABASE:
userLoader = new UserLoader(this);
UserParam param = new UserParam(UserParam.ONLINE, userId);
userLoader.execute(param, this::setUserResult);
// fall through
case UserResult.ONLINE:
if (result.user != null) {
setUser(result.user);
}
break;
case UserResult.ERROR:
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (user == null || (result.exception != null
&& (result.exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND
|| result.exception.getErrorCode() == ConnectionException.USER_NOT_FOUND))) {
finish();
}
break;
}
}
/**
* set user relation information
*
* @param result relation result from async executor
*/
private void setRelationResult(RelationResult result) {
switch (result.mode) {
case RelationResult.BLOCK:
Toast.makeText(getApplicationContext(), R.string.info_user_blocked, Toast.LENGTH_SHORT).show();
break;
case RelationResult.UNBLOCK:
Toast.makeText(getApplicationContext(), R.string.info_user_unblocked, Toast.LENGTH_SHORT).show();
break;
case RelationResult.MUTE:
Toast.makeText(getApplicationContext(), R.string.info_user_muted, Toast.LENGTH_SHORT).show();
break;
case RelationResult.UNMUTE:
Toast.makeText(getApplicationContext(), R.string.info_user_unmuted, Toast.LENGTH_SHORT).show();
break;
case RelationResult.FOLLOW:
Toast.makeText(getApplicationContext(), R.string.info_followed, Toast.LENGTH_SHORT).show();
break;
case RelationResult.UNFOLLOW:
Toast.makeText(getApplicationContext(), R.string.info_unfollowed, Toast.LENGTH_SHORT).show();
break;
case RelationResult.ERROR:
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
break;
}
if (result.relation != null) {
relation = result.relation;
invalidateOptionsMenu();
}
}
/**
* Set User Information
*
* @param user User data
*/
public void setUser(User user) {
private void setUser(@NonNull User user) {
this.user = user;
Spanned bio = Tagger.makeTextWithLinks(user.getDescription(), settings.getHighlightColor(), this);
@ -731,55 +813,4 @@ public class ProfileActivity extends AppCompatActivity implements ActivityResult
follower.setVisibility(VISIBLE);
}
}
/**
* sets user relation information and checks for status changes
*
* @param relation relation to an user
*/
public void onAction(@NonNull Relation relation) {
if (this.relation != null) {
// check if block status changed
if (relation.isBlocked() != this.relation.isBlocked()) {
if (relation.isBlocked()) {
Toast.makeText(getApplicationContext(), R.string.info_user_blocked, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), R.string.info_user_unblocked, Toast.LENGTH_SHORT).show();
}
}
// check if following status changed
else if (relation.isFollowing() != this.relation.isFollowing()) {
if (relation.isFollowing()) {
Toast.makeText(getApplicationContext(), R.string.info_followed, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), R.string.info_unfollowed, Toast.LENGTH_SHORT).show();
}
}
// check if mute status changed
else if (relation.isMuted() != this.relation.isMuted()) {
if (relation.isMuted()) {
Toast.makeText(getApplicationContext(), R.string.info_user_muted, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), R.string.info_user_unmuted, Toast.LENGTH_SHORT).show();
}
}
}
this.relation = relation;
invalidateOptionsMenu();
}
/**
* called if an error occurs
*
* @param exception Engine Exception
*/
public void onError(@Nullable ConnectionException exception) {
String message = ErrorHandler.getErrorMessage(this, exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (user == null || (exception != null
&& (exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND
|| exception.getErrorCode() == ConnectionException.USER_NOT_FOUND))) {
finish();
}
}
}

View File

@ -155,8 +155,8 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
@Override
protected void onDestroy() {
loadingCircle.dismiss();
if (editorAsync != null && !editorAsync.idle())
editorAsync.kill();
if (editorAsync != null && !editorAsync.isIdle())
editorAsync.cancel();
super.onDestroy();
}
@ -252,15 +252,15 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
@Override
public void onResult(UserUpdateResult res) {
if (res.user != null) {
public void onResult(UserUpdateResult result) {
if (result.user != null) {
Intent data = new Intent();
data.putExtra(KEY_UPDATED_PROFILE, res.user);
data.putExtra(KEY_UPDATED_PROFILE, result.user);
Toast.makeText(getApplicationContext(), R.string.info_profile_updated, Toast.LENGTH_SHORT).show();
setResult(RETURN_PROFILE_CHANGED, data);
finish();
} else {
String message = ErrorHandler.getErrorMessage(this, res.exception);
String message = ErrorHandler.getErrorMessage(this, result.exception);
confirmDialog.show(ConfirmDialog.PROFILE_EDITOR_ERROR, message);
loadingCircle.dismiss();
}
@ -284,7 +284,7 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
* update user information
*/
private void updateUser() {
if (editorAsync == null || editorAsync.idle()) {
if (editorAsync == null || editorAsync.isIdle()) {
String username = this.username.getText().toString();
String userLink = profileUrl.getText().toString();
String userLoc = profileLocation.getText().toString();
@ -295,7 +295,7 @@ public class ProfileEditor extends MediaActivity implements OnClickListener, Asy
} else if (!userLink.isEmpty() && !Patterns.WEB_URL.matcher(userLink).matches()) {
String errMsg = getString(R.string.error_invalid_link);
profileUrl.setError(errMsg);
} else if (editorAsync == null || editorAsync.idle()) {
} else if (editorAsync == null || editorAsync.isIdle()) {
holder.setProfile(username, userLink, userBio, userLoc);
if (holder.prepare(getContentResolver())) {
editorAsync = new UserUpdater(this);

View File

@ -1,6 +1,5 @@
package org.nuclearfog.twidda.ui.activities;
import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.GONE;
import static android.view.View.OnClickListener;
import static android.view.View.VISIBLE;
@ -40,23 +39,22 @@ import com.flask.colorpicker.builder.ColorPickerDialogBuilder;
import com.kyleduo.switchbutton.SwitchButton;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.ui.adapter.FontAdapter;
import org.nuclearfog.twidda.ui.adapter.LocationAdapter;
import org.nuclearfog.twidda.ui.adapter.ScaleAdapter;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.LocationLoader;
import org.nuclearfog.twidda.backend.async.LocationLoader.LocationLoaderResult;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.config.Configuration;
import org.nuclearfog.twidda.config.GlobalSettings;
import org.nuclearfog.twidda.database.DatabaseAdapter;
import org.nuclearfog.twidda.model.Location;
import org.nuclearfog.twidda.ui.dialogs.ConfirmDialog;
import org.nuclearfog.twidda.ui.dialogs.ConfirmDialog.OnConfirmListener;
import org.nuclearfog.twidda.ui.dialogs.InfoDialog;
import org.nuclearfog.twidda.ui.dialogs.LicenseDialog;
import java.util.List;
import java.util.regex.Matcher;
/**
@ -65,7 +63,7 @@ import java.util.regex.Matcher;
* @author nuclearfog
*/
public class SettingsActivity extends AppCompatActivity implements OnClickListener, OnDismissListener, OnSeekBarChangeListener,
OnCheckedChangeListener, OnItemSelectedListener, OnConfirmListener, OnColorChangedListener {
OnCheckedChangeListener, OnItemSelectedListener, OnConfirmListener, OnColorChangedListener, AsyncCallback<LocationLoaderResult> {
/**
* return code to recognize {@link MainActivity} that the current account was removed from login
@ -255,9 +253,9 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
super.onStart();
setResult(RETURN_SETTINGS_CHANGED);
if (configuration == Configuration.TWITTER1 || configuration == Configuration.TWITTER2) {
if (locationAsync == null || locationAsync.getStatus() != RUNNING) {
if (locationAsync == null || locationAsync.isIdle()) {
locationAsync = new LocationLoader(this);
locationAsync.execute();
locationAsync.execute(null, this);
}
}
}
@ -275,8 +273,8 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
@Override
protected void onDestroy() {
if (locationAsync != null && locationAsync.getStatus() == RUNNING)
locationAsync.cancel(true);
if (locationAsync != null && !locationAsync.isIdle())
locationAsync.cancel();
super.onDestroy();
}
@ -589,27 +587,19 @@ public class SettingsActivity extends AppCompatActivity implements OnClickListen
settings.setListSize((seekBar.getProgress() + 1) * 10);
}
/**
* set location information from twitter
*
* @param data location data
*/
public void setLocationData(@NonNull List<Location> data) {
locationAdapter.replaceItems(data);
int position = locationAdapter.indexOf(settings.getTrendLocation());
if (position > 0)
locationSpinner.setSelection(position, false);
locationSpinner.setOnItemSelectedListener(this);
}
/**
* called when an error occurs
*
* @param exception exception from twitter
*/
public void onError(@Nullable ConnectionException exception) {
String message = ErrorHandler.getErrorMessage(this, exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
@Override
public void onResult(LocationLoaderResult result) {
if (result.locations != null) {
locationAdapter.replaceItems(result.locations);
int position = locationAdapter.indexOf(settings.getTrendLocation());
if (position > 0)
locationSpinner.setSelection(position, false);
locationSpinner.setOnItemSelectedListener(this);
} else {
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
/**

View File

@ -1,6 +1,5 @@
package org.nuclearfog.twidda.ui.activities;
import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.GONE;
import static android.view.View.OnClickListener;
import static android.view.View.OnLongClickListener;
@ -53,11 +52,14 @@ import org.nuclearfog.tag.Tagger;
import org.nuclearfog.tag.Tagger.OnTagClickListener;
import org.nuclearfog.textviewtool.LinkAndScrollMovement;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.config.Configuration;
import org.nuclearfog.twidda.ui.adapter.PreviewAdapter;
import org.nuclearfog.twidda.ui.adapter.PreviewAdapter.OnCardClickListener;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.StatusAction;
import org.nuclearfog.twidda.backend.async.StatusAction.StatusParam;
import org.nuclearfog.twidda.backend.async.StatusAction.StatusResult;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.backend.utils.PicassoBuilder;
@ -85,7 +87,7 @@ import jp.wasabeef.picasso.transformations.RoundedCornersTransformation;
*
* @author nuclearfog
*/
public class StatusActivity extends AppCompatActivity implements OnClickListener, OnScrollChangeListener,
public class StatusActivity extends AppCompatActivity implements OnClickListener, OnScrollChangeListener, AsyncCallback<StatusResult>,
OnLongClickListener, OnTagClickListener, OnConfirmListener, OnCardClickListener {
/**
@ -211,7 +213,7 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
replyUsername = status.getAuthor().getScreenname();
}
} else {
id = getIntent().getLongExtra(KEY_STATUS_ID, -1);
id = getIntent().getLongExtra(KEY_STATUS_ID, -1L);
}
// initialize status reply list
Bundle param = new Bundle();
@ -265,16 +267,17 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
protected void onStart() {
super.onStart();
if (statusAsync == null) {
statusAsync = new StatusAction(this);
// print status object and get and update it
if (status != null) {
statusAsync = new StatusAction(this, StatusAction.LOAD_ONLINE);
statusAsync.execute(status.getId());
setStatus(status);
StatusParam param = new StatusParam(StatusParam.ONLINE, status.getId());
statusAsync.execute(param, this);
}
// Load status from database first if no status is defined
else {
statusAsync = new StatusAction(this, StatusAction.LOAD_DATABASE);
statusAsync.execute(id);
StatusParam param = new StatusParam(StatusParam.ONLINE, id);
statusAsync.execute(param, this);
}
}
}
@ -282,8 +285,8 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
@Override
protected void onDestroy() {
if (statusAsync != null && statusAsync.getStatus() == RUNNING)
statusAsync.cancel(true);
if (statusAsync != null && !statusAsync.isIdle())
statusAsync.cancel();
super.onDestroy();
}
@ -370,12 +373,14 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
}
// hide status
else if (item.getItemId() == R.id.menu_status_hide) {
StatusParam param;
if (hidden) {
statusAsync = new StatusAction(this, StatusAction.UNHIDE);
param = new StatusParam(StatusParam.UNHIDE, status.getId());
} else {
statusAsync = new StatusAction(this, StatusAction.HIDE);
param = new StatusParam(StatusParam.HIDE, status.getId());
}
statusAsync.execute(this.status.getId());
statusAsync = new StatusAction(this);
statusAsync.execute(param, this);
}
// get status link
else if (item.getItemId() == R.id.menu_status_browser) {
@ -490,30 +495,30 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
@Override
public boolean onLongClick(View v) {
if (status != null && (statusAsync == null || statusAsync.getStatus() != RUNNING)) {
if (status != null && (statusAsync == null || statusAsync.isIdle())) {
// repost this status
if (v.getId() == R.id.page_status_repost) {
StatusParam param;
if (status.isReposted()) {
statusAsync = new StatusAction(this, StatusAction.REMOVE_REPOST);
param = new StatusParam(StatusParam.UNREPOST, status.getId());
} else {
statusAsync = new StatusAction(this, StatusAction.REPOST);
}
if (status.getEmbeddedStatus() != null) {
statusAsync.execute(status.getId(), status.getEmbeddedStatus().getRepostId());
} else {
statusAsync.execute(status.getId());
param = new StatusParam(StatusParam.REPOST, status.getId());
}
statusAsync = new StatusAction(this);
statusAsync.execute(param, this);
Toast.makeText(getApplicationContext(), R.string.info_loading, LENGTH_SHORT).show();
return true;
}
// favorite this status
else if (v.getId() == R.id.page_status_favorite) {
StatusParam param;
if (status.isFavorited()) {
statusAsync = new StatusAction(this, StatusAction.UNFAVORITE);
param = new StatusParam(StatusParam.UNFAVORITE, status.getId());
} else {
statusAsync = new StatusAction(this, StatusAction.FAVORITE);
param = new StatusParam(StatusParam.FAVORITE, status.getId());
}
statusAsync.execute(status.getId());
statusAsync = new StatusAction(this);
statusAsync.execute(param, this);
Toast.makeText(getApplicationContext(), R.string.info_loading, LENGTH_SHORT).show();
return true;
}
@ -544,12 +549,14 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
}
// bookmark status
else if (v.getId() == R.id.page_status_bookmark) {
StatusParam param;
if (status.isBookmarked()) {
statusAsync = new StatusAction(this, StatusAction.UNBOOKMARK);
param = new StatusParam(StatusParam.UNBOOKMARK, status.getId());
} else {
statusAsync = new StatusAction(this, StatusAction.BOOKMARK);
param = new StatusParam(StatusParam.BOOKMARK, status.getId());
}
statusAsync.execute(status.getId());
statusAsync = new StatusAction(this);
statusAsync.execute(param, this);
Toast.makeText(getApplicationContext(), R.string.info_loading, LENGTH_SHORT).show();
return true;
}
@ -577,8 +584,9 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
}
// delete status
if (type == ConfirmDialog.DELETE_STATUS) {
statusAsync = new StatusAction(this, StatusAction.DELETE);
statusAsync.execute(status.getId(), status.getRepostId());
StatusParam param = new StatusParam(StatusParam.DELETE, status.getId());
statusAsync = new StatusAction(this);
statusAsync.execute(param, this);
}
// confirm playing video without proxy
else if (type == ConfirmDialog.PROXY_CONFIRM) {
@ -810,57 +818,62 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
}
}
/**
* called after a status action
*
* @param action action type
*/
public void OnSuccess(int action) {
switch (action) {
case StatusAction.REPOST:
@Override
public void onResult(StatusResult result) {
if (result.status != null) {
setStatus(result.status);
}
switch (result.mode) {
case StatusResult.DATABASE: // update database status
StatusParam param = new StatusParam(StatusParam.ONLINE, id);
statusAsync.execute(param, this);
break;
case StatusResult.REPOST:
Toast.makeText(getApplicationContext(), R.string.info_tweet_retweeted, LENGTH_SHORT).show();
break;
case StatusAction.REMOVE_REPOST:
case StatusResult.UNREPOST:
Toast.makeText(getApplicationContext(), R.string.info_tweet_unretweeted, LENGTH_SHORT).show();
// todo remove old retweet from list fragment
break;
case StatusAction.FAVORITE:
case StatusResult.FAVORITE:
if (settings.likeEnabled())
Toast.makeText(getApplicationContext(), R.string.info_tweet_liked, LENGTH_SHORT).show();
else
Toast.makeText(getApplicationContext(), R.string.info_tweet_favored, LENGTH_SHORT).show();
break;
case StatusAction.UNFAVORITE:
case StatusResult.UNFAVORITE:
if (settings.likeEnabled())
Toast.makeText(getApplicationContext(), R.string.info_tweet_unliked, LENGTH_SHORT).show();
else
Toast.makeText(getApplicationContext(), R.string.info_tweet_unfavored, LENGTH_SHORT).show();
break;
case StatusAction.BOOKMARK:
case StatusResult.BOOKMARK:
Toast.makeText(getApplicationContext(), R.string.info_tweet_bookmarked, LENGTH_SHORT).show();
break;
case StatusAction.UNBOOKMARK:
case StatusResult.UNBOOKMARK:
Toast.makeText(getApplicationContext(), R.string.info_tweet_unbookmarked, LENGTH_SHORT).show();
break;
case StatusAction.HIDE:
case StatusResult.HIDE:
hidden = true;
invalidateOptionsMenu();
Toast.makeText(getApplicationContext(), R.string.info_reply_hidden, LENGTH_SHORT).show();
break;
case StatusAction.UNHIDE:
case StatusResult.UNHIDE:
hidden = false;
invalidateOptionsMenu();
Toast.makeText(getApplicationContext(), R.string.info_reply_unhidden, LENGTH_SHORT).show();
break;
case StatusAction.DELETE:
case StatusResult.DELETE:
if (status != null) {
Toast.makeText(getApplicationContext(), R.string.info_tweet_removed, LENGTH_SHORT).show();
Intent returnData = new Intent();
@ -872,25 +885,20 @@ public class StatusActivity extends AppCompatActivity implements OnClickListener
finish();
}
break;
}
}
/**
* called when an error occurs
*
* @param exception Error information
*/
public void onError(@Nullable ConnectionException exception) {
String message = ErrorHandler.getErrorMessage(this, exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (status == null) {
finish();
} else if (exception != null && exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
// Mark status as removed, so it can be removed from the list
Intent returnData = new Intent();
returnData.putExtra(INTENT_STATUS_REMOVED_ID, status.getId());
setResult(RETURN_STATUS_REMOVED, returnData);
finish();
case StatusResult.ERROR:
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (status == null) {
finish();
} else if (result.exception != null && result.exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
// Mark status as removed, so it can be removed from the list
Intent returnData = new Intent();
returnData.putExtra(INTENT_STATUS_REMOVED_ID, status.getId());
setResult(RETURN_STATUS_REMOVED, returnData);
finish();
}
break;
}
}
}

View File

@ -1,12 +1,6 @@
package org.nuclearfog.twidda.ui.activities;
import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.GONE;
import static android.view.View.INVISIBLE;
import static android.view.View.OnClickListener;
import static android.view.View.VISIBLE;
import static android.widget.Toast.LENGTH_LONG;
import static android.widget.Toast.LENGTH_SHORT;
import android.content.Context;
import android.content.Intent;
@ -28,10 +22,11 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.ui.adapter.IconAdapter;
import org.nuclearfog.twidda.ui.adapter.IconAdapter.OnMediaClickListener;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.StatusUpdater;
import org.nuclearfog.twidda.backend.async.StatusUpdater.StatusUpdateResult;
import org.nuclearfog.twidda.backend.helper.StatusUpdate;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
@ -46,7 +41,8 @@ import org.nuclearfog.twidda.ui.dialogs.ProgressDialog.OnProgressStopListener;
*
* @author nuclearfog
*/
public class StatusEditor extends MediaActivity implements OnClickListener, OnProgressStopListener, OnConfirmListener, OnMediaClickListener, TextWatcher {
public class StatusEditor extends MediaActivity implements OnClickListener, OnProgressStopListener, OnConfirmListener,
OnMediaClickListener, AsyncCallback<StatusUpdateResult>, TextWatcher {
/**
* key to add a statusd ID to reply
@ -99,7 +95,7 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
AppStyles.setEditorTheme(root, background);
if (!settings.getLogin().getConfiguration().locationSupported()) {
locationBtn.setVisibility(GONE);
locationBtn.setVisibility(View.GONE);
}
long inReplyId = getIntent().getLongExtra(KEY_STATUS_EDITOR_REPLYID, 0);
String prefix = getIntent().getStringExtra(KEY_STATUS_EDITOR_TEXT);
@ -128,11 +124,11 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
super.onResume();
if (settings.getLogin().getConfiguration().locationSupported()) {
if (isLocating()) {
locationPending.setVisibility(VISIBLE);
locationBtn.setVisibility(INVISIBLE);
locationPending.setVisibility(View.VISIBLE);
locationBtn.setVisibility(View.INVISIBLE);
} else {
locationPending.setVisibility(INVISIBLE);
locationBtn.setVisibility(VISIBLE);
locationPending.setVisibility(View.INVISIBLE);
locationBtn.setVisibility(View.VISIBLE);
}
}
}
@ -141,8 +137,8 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
@Override
protected void onDestroy() {
loadingCircle.dismiss();
if (uploaderAsync != null && uploaderAsync.getStatus() == RUNNING)
uploaderAsync.cancel(true);
if (uploaderAsync != null && !uploaderAsync.isIdle())
uploaderAsync.cancel();
super.onDestroy();
}
@ -159,14 +155,14 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
if (v.getId() == R.id.popup_status_send) {
// check if status is empty
if (statusUpdate.isEmpty()) {
Toast.makeText(getApplicationContext(), R.string.error_empty_tweet, LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(), R.string.error_empty_tweet, Toast.LENGTH_SHORT).show();
}
// check if GPS location is pending
else if (isLocating()) {
Toast.makeText(getApplicationContext(), R.string.info_location_pending, LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(), R.string.info_location_pending, Toast.LENGTH_SHORT).show();
}
// check if gps locating is not pending
else if (uploaderAsync == null || uploaderAsync.getStatus() != RUNNING) {
else if (uploaderAsync == null || uploaderAsync.isIdle()) {
updateStatus();
}
}
@ -186,8 +182,8 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
}
// add location to the status
else if (v.getId() == R.id.popup_status_add_location) {
locationPending.setVisibility(VISIBLE);
locationBtn.setVisibility(INVISIBLE);
locationPending.setVisibility(View.VISIBLE);
locationBtn.setVisibility(View.INVISIBLE);
getLocation();
}
}
@ -213,12 +209,12 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
protected void onAttachLocation(@Nullable Location location) {
if (location != null) {
statusUpdate.addLocation(location);
Toast.makeText(getApplicationContext(), R.string.info_gps_attached, LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), R.string.info_gps_attached, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), R.string.error_gps, LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), R.string.error_gps, Toast.LENGTH_LONG).show();
}
locationPending.setVisibility(INVISIBLE);
locationBtn.setVisibility(VISIBLE);
locationPending.setVisibility(View.INVISIBLE);
locationBtn.setVisibility(View.VISIBLE);
}
@ -239,19 +235,19 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
break;
case StatusUpdate.MEDIA_ERROR:
Toast.makeText(getApplicationContext(), R.string.error_adding_media, LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(), R.string.error_adding_media, Toast.LENGTH_SHORT).show();
break;
}
if (statusUpdate.mediaLimitReached()) {
mediaBtn.setVisibility(GONE);
mediaBtn.setVisibility(View.GONE);
}
}
@Override
public void stopProgress() {
if (uploaderAsync != null && uploaderAsync.getStatus() == RUNNING) {
uploaderAsync.cancel(true);
if (uploaderAsync != null && !uploaderAsync.isIdle()) {
uploaderAsync.cancel();
}
}
@ -289,21 +285,17 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
}
}
/**
* called if status was updated successfully
*/
public void onSuccess() {
Toast.makeText(getApplicationContext(), R.string.info_tweet_sent, LENGTH_LONG).show();
finish();
}
/**
* Show confirmation dialog if an error occurs while sending status
*/
public void onError(@Nullable ConnectionException exception) {
String message = ErrorHandler.getErrorMessage(this, exception);
confirmDialog.show(ConfirmDialog.STATUS_EDITOR_ERROR, message);
loadingCircle.dismiss();
@Override
public void onResult(StatusUpdateResult result) {
if (result.success) {
Toast.makeText(getApplicationContext(), R.string.info_tweet_sent, Toast.LENGTH_LONG).show();
finish();
} else {
String message = ErrorHandler.getErrorMessage(this, result.exception);
confirmDialog.show(ConfirmDialog.STATUS_EDITOR_ERROR, message);
loadingCircle.dismiss();
}
}
/**
@ -325,11 +317,11 @@ public class StatusEditor extends MediaActivity implements OnClickListener, OnPr
if (statusUpdate.prepare(getContentResolver())) {
// send status
uploaderAsync = new StatusUpdater(this);
uploaderAsync.execute(statusUpdate);
uploaderAsync.execute(statusUpdate, this);
// show progress dialog
loadingCircle.show();
} else {
Toast.makeText(getApplicationContext(), R.string.error_media_init, LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(), R.string.error_media_init, Toast.LENGTH_SHORT).show();
}
}
}

View File

@ -1,6 +1,5 @@
package org.nuclearfog.twidda.ui.activities;
import static android.os.AsyncTask.Status.RUNNING;
import static org.nuclearfog.twidda.ui.activities.UserlistEditor.KEY_LIST_EDITOR_DATA;
import android.content.Context;
@ -33,7 +32,11 @@ import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.ui.adapter.FragmentAdapter;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.ListAction;
import org.nuclearfog.twidda.backend.async.ListAction.ListActionParam;
import org.nuclearfog.twidda.backend.async.ListAction.ListActionResult;
import org.nuclearfog.twidda.backend.async.ListManager;
import org.nuclearfog.twidda.backend.async.ListManager.ListManagerParam;
import org.nuclearfog.twidda.backend.async.ListManager.ListManagerResult;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.config.GlobalSettings;
@ -158,8 +161,9 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
boolean blockUpdate = getIntent().getBooleanExtra(KEY_LIST_NO_UPDATE, false);
if (!blockUpdate) {
// update list information
listLoaderAsync = new ListAction(this, userList.getId(), ListAction.LOAD);
listLoaderAsync.execute();
listLoaderAsync = new ListAction(this);
ListActionParam param = new ListActionParam(ListActionParam.LOAD, userList.getId());
listLoaderAsync.execute(param, this::setList);
}
}
}
@ -167,8 +171,8 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
@Override
protected void onDestroy() {
if (listLoaderAsync != null && listLoaderAsync.getStatus() == RUNNING) {
listLoaderAsync.cancel(true);
if (listLoaderAsync != null && !listLoaderAsync.isIdle()) {
listLoaderAsync.cancel();
}
super.onDestroy();
}
@ -213,7 +217,7 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (userList != null && (listLoaderAsync == null || listLoaderAsync.getStatus() != RUNNING)) {
if (userList != null && (listLoaderAsync == null || listLoaderAsync.isIdle())) {
// open user list editor
if (item.getItemId() == R.id.menu_list_edit) {
Intent editList = new Intent(this, UserlistEditor.class);
@ -229,8 +233,9 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
if (userList.isFollowing()) {
confirmDialog.show(ConfirmDialog.LIST_UNFOLLOW);
} else {
listLoaderAsync = new ListAction(this, userList.getId(), ListAction.FOLLOW);
listLoaderAsync.execute();
listLoaderAsync = new ListAction(this);
ListActionParam param = new ListActionParam(ListActionParam.FOLLOW, userList.getId());
listLoaderAsync.execute(param, this::setList);
}
}
// theme expanded search view
@ -277,23 +282,26 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
if (userList != null) {
// delete user list
if (type == ConfirmDialog.LIST_DELETE) {
if (listLoaderAsync == null || listLoaderAsync.getStatus() != RUNNING) {
listLoaderAsync = new ListAction(this, userList.getId(), ListAction.DELETE);
listLoaderAsync.execute();
if (listLoaderAsync == null || listLoaderAsync.isIdle()) {
ListActionParam param = new ListActionParam(ListActionParam.DELETE, userList.getId());
listLoaderAsync = new ListAction(this);
listLoaderAsync.execute(param, this::setList);
}
}
// unfollow user list
else if (type == ConfirmDialog.LIST_UNFOLLOW) {
if (listLoaderAsync == null || listLoaderAsync.getStatus() != RUNNING) {
listLoaderAsync = new ListAction(this, userList.getId(), ListAction.UNFOLLOW);
listLoaderAsync.execute();
if (listLoaderAsync == null || listLoaderAsync.isIdle()) {
ListActionParam param = new ListActionParam(ListActionParam.UNFOLLOW, userList.getId());
listLoaderAsync = new ListAction(this);
listLoaderAsync.execute(param, this::setList);
}
}
// remove user from list
else if (type == ConfirmDialog.LIST_REMOVE_USER) {
if ((listManagerAsync == null || listManagerAsync.getStatus() != RUNNING) && user != null) {
listManagerAsync = new ListManager(this, userList.getId(), ListManager.DEL_USER, user.getScreenname(), this);
listManagerAsync.execute();
if ((listManagerAsync == null || listManagerAsync.isIdle()) && user != null) {
ListManagerParam param = new ListManagerParam(ListManagerParam.DEL_USER, userList.getId(), user.getScreenname());
listManagerAsync = new ListManager(this);
listManagerAsync.execute(param, this::updateList);
}
}
}
@ -328,10 +336,11 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
if (userList == null)
return false;
if (USERNAME_PATTERN.matcher(query).matches()) {
if (listManagerAsync == null || listManagerAsync.getStatus() != RUNNING) {
if (listManagerAsync == null || listManagerAsync.isIdle()) {
Toast.makeText(getApplicationContext(), R.string.info_adding_user_to_list, Toast.LENGTH_SHORT).show();
listManagerAsync = new ListManager(this, userList.getId(), ListManager.ADD_USER, query, this);
listManagerAsync.execute();
ListManagerParam param = new ListManagerParam(ListManagerParam.ADD_USER, userList.getId(), query);
listManagerAsync = new ListManager(this);
listManagerAsync.execute(param, this::updateList);
return true;
}
} else {
@ -340,44 +349,6 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
return false;
}
/**
* called from {@link ListManager}
*
* @param action what action was taken
* @param name screen name of the list member
*/
public void onSuccess(int action, String name) {
switch (action) {
case ListManager.ADD_USER:
if (!name.startsWith("@"))
name = '@' + name;
String info = getString(R.string.info_user_added_to_list, name);
Toast.makeText(getApplicationContext(), info, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
break;
case ListManager.DEL_USER:
if (user != null) {
info = getString(R.string.info_user_removed, user.getScreenname());
Toast.makeText(getApplicationContext(), info, Toast.LENGTH_SHORT).show();
// remove user from list member page
Fragment fragment = adapter.getItem(1);
if (fragment instanceof UserFragment) {
UserFragment callback = (UserFragment) fragment;
callback.removeUser(user);
}
}
break;
}
}
/**
* called from {@link ListManager} when an error occurs
*/
public void onFailure(@Nullable ConnectionException exception) {
String message = ErrorHandler.getErrorMessage(this, exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
/**
* called from {@link org.nuclearfog.twidda.ui.fragments.UserFragment} when an user should be removed from a list
@ -392,54 +363,86 @@ public class UserlistActivity extends AppCompatActivity implements ActivityResul
}
/**
* called from {@link ListAction} to update userlist information
*
* @param userList userlist update
* update userlist member
*/
public void onSuccess(@NonNull UserList userList, int action) {
this.userList = userList;
switch (action) {
case ListAction.LOAD:
toolbar.setTitle(userList.getTitle());
toolbar.setSubtitle(userList.getDescription());
public void updateList(ListManagerResult result) {
switch (result.mode) {
case ListManagerResult.ADD_USER:
String name;
if (!result.name.startsWith("@"))
name = '@' + result.name;
else
name = result.name;
String info = getString(R.string.info_user_added_to_list, name);
Toast.makeText(getApplicationContext(), info, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
break;
case ListAction.FOLLOW:
Toast.makeText(getApplicationContext(), R.string.info_list_followed, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
case ListManagerResult.DEL_USER:
if (user != null) {
info = getString(R.string.info_user_removed, user.getScreenname());
Toast.makeText(getApplicationContext(), info, Toast.LENGTH_SHORT).show();
// remove user from list member page
Fragment fragment = adapter.getItem(1);
if (fragment instanceof UserFragment) {
UserFragment callback = (UserFragment) fragment;
callback.removeUser(user);
}
}
break;
case ListAction.UNFOLLOW:
Toast.makeText(getApplicationContext(), R.string.info_list_unfollowed, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
break;
case ListAction.DELETE:
Intent result = new Intent();
result.putExtra(RESULT_REMOVED_LIST_ID, userList.getId());
setResult(RETURN_LIST_REMOVED, result);
Toast.makeText(getApplicationContext(), R.string.info_list_removed, Toast.LENGTH_SHORT).show();
finish();
case ListManagerResult.ERROR:
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
break;
}
}
/**
* called from {@link ListAction} if an error occurs
*
* @param exception error information
* @param listId ID of the list where an error occurred
* update userlist content
*/
public void onFailure(@Nullable ConnectionException exception, long listId) {
String message = ErrorHandler.getErrorMessage(this, exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (exception != null && exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
// List does not exist
Intent result = new Intent();
result.putExtra(RESULT_REMOVED_LIST_ID, listId);
setResult(RETURN_LIST_REMOVED, result);
finish();
private void setList(ListActionResult result) {
switch (result.mode) {
case ListActionResult.LOAD:
if (result.userlist != null) {
toolbar.setTitle(result.userlist.getTitle());
toolbar.setSubtitle(result.userlist.getDescription());
invalidateOptionsMenu();
}
break;
case ListActionResult.FOLLOW:
Toast.makeText(getApplicationContext(), R.string.info_list_followed, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
break;
case ListActionResult.UNFOLLOW:
Toast.makeText(getApplicationContext(), R.string.info_list_unfollowed, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
break;
case ListActionResult.DELETE:
Intent intent = new Intent();
intent.putExtra(RESULT_REMOVED_LIST_ID, result.userlist);
setResult(RETURN_LIST_REMOVED, intent);
Toast.makeText(getApplicationContext(), R.string.info_list_removed, Toast.LENGTH_SHORT).show();
finish();
break;
case ListActionResult.ERROR:
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
if (result.exception != null && result.exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
// List does not exist
intent = new Intent();
intent.putExtra(RESULT_REMOVED_LIST_ID, result.id);
setResult(RETURN_LIST_REMOVED, intent);
finish();
}
break;
}
if (result.userlist != null) {
this.userList = result.userlist;
}
}
}

View File

@ -1,7 +1,5 @@
package org.nuclearfog.twidda.ui.activities;
import static android.os.AsyncTask.Status.RUNNING;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@ -15,15 +13,15 @@ import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.ListUpdater;
import org.nuclearfog.twidda.backend.async.ListUpdater.ListUpdateResult;
import org.nuclearfog.twidda.backend.helper.UserListUpdate;
import org.nuclearfog.twidda.backend.utils.AppStyles;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.model.UserList;
import org.nuclearfog.twidda.ui.dialogs.ConfirmDialog;
@ -36,7 +34,7 @@ import org.nuclearfog.twidda.ui.dialogs.ProgressDialog.OnProgressStopListener;
*
* @author nuclearfog
*/
public class UserlistEditor extends AppCompatActivity implements OnClickListener, OnConfirmListener, OnProgressStopListener {
public class UserlistEditor extends AppCompatActivity implements OnClickListener, OnConfirmListener, OnProgressStopListener, AsyncCallback<ListUpdateResult> {
/**
* Key for the list ID if an existing list should be updated
@ -135,7 +133,7 @@ public class UserlistEditor extends AppCompatActivity implements OnClickListener
@Override
public void onClick(View view) {
if (view.getId() == R.id.userlist_create_list) {
if (updaterAsync == null || updaterAsync.getStatus() != RUNNING) {
if (updaterAsync == null || updaterAsync.isIdle()) {
updateList();
}
}
@ -144,8 +142,8 @@ public class UserlistEditor extends AppCompatActivity implements OnClickListener
@Override
public void stopProgress() {
if (updaterAsync != null && updaterAsync.getStatus() == RUNNING) {
updaterAsync.cancel(true);
if (updaterAsync != null && !updaterAsync.isIdle()) {
updaterAsync.cancel();
}
}
@ -162,31 +160,24 @@ public class UserlistEditor extends AppCompatActivity implements OnClickListener
}
}
/**
* called when a list was created successfully
*
* @param result new created list
* @param updated true if an existing list was updated
*/
public void onSuccess(@NonNull UserList result, boolean updated) {
if (updated) {
Toast.makeText(getApplicationContext(), R.string.info_list_updated, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), R.string.info_list_created, Toast.LENGTH_SHORT).show();
}
Intent data = new Intent();
data.putExtra(KEY_UPDATED_USERLIST, result);
setResult(RETURN_LIST_CHANGED, data);
finish();
}
/**
* called when an error occurs while updating a list
*/
public void onError(@Nullable ConnectionException exception) {
String message = ErrorHandler.getErrorMessage(this, exception);
confirmDialog.show(ConfirmDialog.LIST_EDITOR_ERROR, message);
loadingCircle.dismiss();
@Override
public void onResult(ListUpdateResult result) {
if (result.userlist != null) {
if (result.updated) {
Toast.makeText(getApplicationContext(), R.string.info_list_updated, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), R.string.info_list_created, Toast.LENGTH_SHORT).show();
}
Intent intent = new Intent();
intent.putExtra(KEY_UPDATED_USERLIST, result.userlist);
setResult(RETURN_LIST_CHANGED, intent);
finish();
} else {
String message = ErrorHandler.getErrorMessage(this, result.exception);
confirmDialog.show(ConfirmDialog.LIST_EDITOR_ERROR, message);
loadingCircle.dismiss();
}
}
/**
@ -207,8 +198,8 @@ public class UserlistEditor extends AppCompatActivity implements OnClickListener
// create new one
mHolder = new UserListUpdate(titleStr, descrStr, isPublic, UserListUpdate.NEW_LIST);
}
updaterAsync = new ListUpdater(this, mHolder);
updaterAsync.execute();
updaterAsync = new ListUpdater(this);
updaterAsync.execute(mHolder, this);
loadingCircle.show();
}
}

View File

@ -232,10 +232,10 @@ public class UsersActivity extends AppCompatActivity implements OnTabSelectedLis
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == R.id.menu_exclude_refresh) {
if (userExclTask == null || userExclTask.idle()) {
if (userExclTask == null || userExclTask.isIdle()) {
Toast.makeText(getApplicationContext(), R.string.info_refreshing_exclude_list, Toast.LENGTH_SHORT).show();
userExclTask = new FilterLoader(this);
FilterParam param = new FilterParam(FilterLoader.MODE_RELOAD);
FilterParam param = new FilterParam(FilterParam.RELOAD);
userExclTask.execute(param, this);
}
}
@ -265,14 +265,14 @@ public class UsersActivity extends AppCompatActivity implements OnTabSelectedLis
@Override
public boolean onQueryTextSubmit(String query) {
if (USERNAME_PATTERN.matcher(query).matches()) {
if (userExclTask == null || userExclTask.idle()) {
if (userExclTask == null || userExclTask.isIdle()) {
if (tablayout.getSelectedTabPosition() == 0) {
userExclTask = new FilterLoader(this);
FilterParam param = new FilterParam(FilterLoader.MODE_MUTE, query);
FilterParam param = new FilterParam(FilterParam.MUTE, query);
userExclTask.execute(param, this);
return true;
} else if (tablayout.getSelectedTabPosition() == 1) {
FilterParam param = new FilterParam(FilterLoader.MODE_BLOCK, query);
FilterParam param = new FilterParam(FilterParam.BLOCK, query);
userExclTask.execute(param, this);
return true;
}
@ -291,25 +291,25 @@ public class UsersActivity extends AppCompatActivity implements OnTabSelectedLis
@Override
public void onResult(FilterResult res) {
switch (res.mode) {
case FilterLoader.MODE_MUTE:
public void onResult(FilterResult result) {
switch (result.mode) {
case FilterResult.MUTE:
Toast.makeText(getApplicationContext(), R.string.info_user_muted, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
break;
case FilterLoader.MODE_BLOCK:
case FilterResult.BLOCK:
Toast.makeText(getApplicationContext(), R.string.info_user_blocked, Toast.LENGTH_SHORT).show();
invalidateOptionsMenu();
break;
case FilterLoader.MODE_RELOAD:
case FilterResult.RELOAD:
Toast.makeText(getApplicationContext(), R.string.info_exclude_list_updated, Toast.LENGTH_SHORT).show();
break;
default:
case FilterLoader.MODE_ERROR:
String message = ErrorHandler.getErrorMessage(this, res.exception);
case FilterResult.ERROR:
String message = ErrorHandler.getErrorMessage(this, result.exception);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
break;
}

View File

@ -53,29 +53,29 @@ public class AccountFragment extends ListFragment implements OnAccountClickListe
super.onStart();
if (loginTask == null) {
setRefresh(true);
load(AccountLoader.MODE_LOAD);
load(AccountParameter.LOAD);
}
}
@Override
public void onDestroy() {
if (loginTask != null && !loginTask.idle())
loginTask.kill();
if (loginTask != null && !loginTask.isIdle())
loginTask.cancel();
super.onDestroy();
}
@Override
protected void onReload() {
load(AccountLoader.MODE_LOAD);
load(AccountParameter.LOAD);
}
@Override
protected void onReset() {
setRefresh(true);
load(AccountLoader.MODE_LOAD);
load(AccountParameter.LOAD);
}
@ -104,26 +104,26 @@ public class AccountFragment extends ListFragment implements OnAccountClickListe
@Override
public void onConfirm(int type, boolean rememberChoice) {
if (type == ConfirmDialog.REMOVE_ACCOUNT) {
load(AccountLoader.MODE_DELETE);
load(AccountParameter.DELETE);
}
}
@Override
public void onResult(AccountResult res) {
switch(res.mode) {
case AccountLoader.MODE_LOAD:
if (res.accounts != null) {
adapter.replaceItems(res.accounts);
public void onResult(AccountResult result) {
switch(result.mode) {
case AccountResult.LOAD:
if (result.accounts != null) {
adapter.replaceItems(result.accounts);
setRefresh(false);
} else {
Toast.makeText(requireContext(), R.string.error_acc_loading, Toast.LENGTH_SHORT).show();
}
break;
case AccountLoader.MODE_DELETE:
if (res.id > 0)
adapter.removeItem(res.id);
case AccountResult.DELETE:
if (result.id > 0)
adapter.removeItem(result.id);
break;
}
}

View File

@ -1,6 +1,5 @@
package org.nuclearfog.twidda.ui.fragments;
import static android.os.AsyncTask.Status.RUNNING;
import static android.widget.Toast.LENGTH_SHORT;
import static org.nuclearfog.twidda.ui.activities.MessageEditor.KEY_DM_PREFIX;
import static org.nuclearfog.twidda.ui.activities.ProfileActivity.KEY_PROFILE_USER;
@ -20,11 +19,13 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.nuclearfog.twidda.R;
import org.nuclearfog.twidda.backend.utils.AsyncExecutor.AsyncCallback;
import org.nuclearfog.twidda.ui.adapter.MessageAdapter;
import org.nuclearfog.twidda.ui.adapter.MessageAdapter.OnMessageClickListener;
import org.nuclearfog.twidda.backend.api.ConnectionException;
import org.nuclearfog.twidda.backend.async.MessageLoader;
import org.nuclearfog.twidda.backend.helper.Messages;
import org.nuclearfog.twidda.backend.async.MessageLoader.MessageLoaderParam;
import org.nuclearfog.twidda.backend.async.MessageLoader.MessageLoaderResult;
import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.model.Message;
import org.nuclearfog.twidda.ui.activities.ImageViewer;
@ -42,7 +43,7 @@ import java.util.List;
*
* @author nuclearfog
*/
public class MessageFragment extends ListFragment implements OnMessageClickListener, OnConfirmListener {
public class MessageFragment extends ListFragment implements OnMessageClickListener, OnConfirmListener, AsyncCallback<MessageLoaderResult> {
private MessageLoader messageTask;
private MessageAdapter adapter;
@ -66,8 +67,7 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
public void onStart() {
super.onStart();
if (messageTask == null) {
load(MessageLoader.DB, null);
setRefresh(true);
loadMessages(false, null);
}
}
@ -75,23 +75,21 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
@Override
protected void onReset() {
adapter = new MessageAdapter(requireContext(), this);
setAdapter(adapter);
load(MessageLoader.DB, null);
setRefresh(true);
loadMessages(false, null);
}
@Override
public void onDestroy() {
if (messageTask != null && messageTask.getStatus() == RUNNING)
messageTask.cancel(true);
if (messageTask != null && !messageTask.isIdle())
messageTask.cancel();
super.onDestroy();
}
@Override
protected void onReload() {
load(MessageLoader.LOAD, null);
loadMessages(true, null);
}
@ -140,7 +138,7 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
break;
case DELETE:
if (!confirmDialog.isShowing() && messageTask != null && messageTask.getStatus() != RUNNING) {
if (!confirmDialog.isShowing() && messageTask != null && messageTask.isIdle()) {
deleteId = message.getId();
confirmDialog.show(ConfirmDialog.MESSAGE_DELETE);
}
@ -169,8 +167,8 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
@Override
public boolean onPlaceholderClick(String cursor) {
if (messageTask != null && messageTask.getStatus() != RUNNING) {
load(MessageLoader.LOAD, cursor);
if (messageTask != null && messageTask.isIdle()) {
loadMessages(false, cursor);
return true;
}
return false;
@ -180,54 +178,54 @@ public class MessageFragment extends ListFragment implements OnMessageClickListe
@Override
public void onConfirm(int type, boolean rememberChoice) {
if (type == ConfirmDialog.MESSAGE_DELETE) {
if (messageTask != null && messageTask.getStatus() != RUNNING) {
messageTask = new MessageLoader(this, MessageLoader.DEL, null, deleteId);
messageTask.execute();
if (messageTask != null && messageTask.isIdle()) {
MessageLoaderParam param = new MessageLoaderParam(MessageLoaderParam.DELETE, deleteId, "");
messageTask = new MessageLoader(requireContext());
messageTask.execute(param, this);
}
}
}
/**
* set data to list
*
* @param data list of direct messages
*/
public void setData(@NonNull Messages data) {
adapter.addItems(data);
@Override
public void onResult(MessageLoaderResult result) {
setRefresh(false);
}
switch (result.mode) {
case MessageLoaderResult.DATABASE:
case MessageLoaderResult.ONLINE:
if (result.messages != null) {
adapter.addItems(result.messages);
}
break;
/**
* remove item from list
*
* @param id ID of the item
*/
public void removeItem(long id) {
Toast.makeText(requireContext(), R.string.info_dm_removed, LENGTH_SHORT).show();
adapter.removeItem(id);
}
case MessageLoaderResult.DELETE:
Toast.makeText(requireContext(), R.string.info_dm_removed, LENGTH_SHORT).show();
adapter.removeItem(result.id);
break;
/**
* called from {@link MessageLoader} if an error occurs
*
* @param messageId ID of the message assosiated with the error
*/
public void onError(@Nullable ConnectionException exception, long messageId) {
String message = ErrorHandler.getErrorMessage(requireContext(), exception);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
if (exception != null && exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
adapter.removeItem(messageId);
case MessageLoaderResult.ERROR:
String message = ErrorHandler.getErrorMessage(requireContext(), result.exception);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
if (result.exception != null && result.exception.getErrorCode() == ConnectionException.RESOURCE_NOT_FOUND) {
adapter.removeItem(result.id);
}
break;
}
setRefresh(false);
}
/**
* load content into the list
*
* @param action mode for loading or removing messages
* @param local true to load message from database
* @param cursor list cursor
*/
private void load(int action, String cursor) {
messageTask = new MessageLoader(this, action, cursor, -1L);
messageTask.execute();
private void loadMessages(boolean local, String cursor) {
MessageLoaderParam param;
if (local) {
param = new MessageLoaderParam(MessageLoaderParam.ONLINE, 0L, cursor);
} else {
param = new MessageLoaderParam(MessageLoaderParam.DATABASE, 0L, cursor);
}
messageTask = new MessageLoader(requireContext());
messageTask.execute(param, this);
setRefresh(true);
}
}

View File

@ -61,8 +61,8 @@ public class NotificationFragment extends ListFragment implements OnNotification
@Override
public void onDestroyView() {
if (notificationAsync != null && !notificationAsync.idle()) {
notificationAsync.kill();
if (notificationAsync != null && !notificationAsync.isIdle()) {
notificationAsync.cancel();
}
super.onDestroyView();
}
@ -107,7 +107,7 @@ public class NotificationFragment extends ListFragment implements OnNotification
@Override
public boolean onPlaceholderClick(long sinceId, long maxId, int position) {
if (notificationAsync != null && notificationAsync.idle()) {
if (notificationAsync != null && notificationAsync.isIdle()) {
load(sinceId, maxId, position);
return true;
}
@ -129,12 +129,12 @@ public class NotificationFragment extends ListFragment implements OnNotification
@Override
public void onResult(NotificationResult res) {
public void onResult(NotificationResult result) {
setRefresh(false);
if (res.notifications != null) {
adapter.addItems(res.notifications, res.position);
if (result.notifications != null) {
adapter.addItems(result.notifications, result.position);
} else {
String message = ErrorHandler.getErrorMessage(requireContext(), res.exception);
String message = ErrorHandler.getErrorMessage(requireContext(), result.exception);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
adapter.disableLoading();
}

View File

@ -156,8 +156,8 @@ public class StatusFragment extends ListFragment implements StatusSelectListener
@Override
public void onDestroy() {
if (statusAsync != null && !statusAsync.idle()) {
statusAsync.kill();
if (statusAsync != null && !statusAsync.isIdle()) {
statusAsync.cancel();
}
super.onDestroy();
}
@ -202,7 +202,7 @@ public class StatusFragment extends ListFragment implements StatusSelectListener
@Override
public boolean onPlaceholderClick(long minId, long maxId, int pos) {
if (statusAsync != null && statusAsync.idle()) {
if (statusAsync != null && statusAsync.isIdle()) {
load(minId, maxId, pos);
return true;
}
@ -211,16 +211,16 @@ public class StatusFragment extends ListFragment implements StatusSelectListener
@Override
public void onResult(StatusResult res) {
public void onResult(StatusResult result) {
setRefresh(false);
if (res.statuses != null) {
if (res.position == CLEAR_LIST) {
adapter.replaceItems(res.statuses);
if (result.statuses != null) {
if (result.position == CLEAR_LIST) {
adapter.replaceItems(result.statuses);
} else {
adapter.addItems(res.statuses, res.position);
adapter.addItems(result.statuses, result.position);
}
} else {
String message = ErrorHandler.getErrorMessage(requireContext(), res.exception);
String message = ErrorHandler.getErrorMessage(requireContext(), result.exception);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
adapter.disableLoading();
setRefresh(false);

View File

@ -71,8 +71,8 @@ public class TrendFragment extends ListFragment implements TrendClickListener, A
@Override
public void onDestroy() {
if (trendTask != null && !trendTask.idle())
trendTask.kill();
if (trendTask != null && !trendTask.isIdle())
trendTask.cancel();
super.onDestroy();
}
@ -97,12 +97,12 @@ public class TrendFragment extends ListFragment implements TrendClickListener, A
@Override
public void onResult(TrendResult res) {
public void onResult(TrendResult result) {
setRefresh(false);
if (res.trends != null) {
adapter.replaceItems(res.trends);
if (result.trends != null) {
adapter.replaceItems(result.trends);
} else {
String message = ErrorHandler.getErrorMessage(requireContext(), res.exception);
String message = ErrorHandler.getErrorMessage(requireContext(), result.exception);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
setRefresh(false);
}

View File

@ -182,8 +182,8 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
@Override
public void onDestroy() {
if (userAsync != null && !userAsync.idle())
userAsync.kill();
if (userAsync != null && !userAsync.isIdle())
userAsync.cancel();
super.onDestroy();
}
@ -219,7 +219,7 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
@Override
public boolean onPlaceholderClick(long cursor) {
if (userAsync != null && userAsync.idle()) {
if (userAsync != null && userAsync.isIdle()) {
load(cursor);
return true;
}
@ -238,12 +238,12 @@ public class UserFragment extends ListFragment implements UserClickListener, Asy
@Override
public void onResult(UserResult res) {
public void onResult(UserResult result) {
setRefresh(false);
if (res.users != null) {
adapter.addItems(res.users);
if (result.users != null) {
adapter.addItems(result.users);
} else {
String message = ErrorHandler.getErrorMessage(requireContext(), res.exception);
String message = ErrorHandler.getErrorMessage(requireContext(), result.exception);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
adapter.disableLoading();
}

View File

@ -103,8 +103,8 @@ public class UserListFragment extends ListFragment implements ListClickListener,
@Override
public void onDestroy() {
if (listTask != null && !listTask.idle())
listTask.kill();
if (listTask != null && !listTask.isIdle())
listTask.cancel();
super.onDestroy();
}
@ -154,7 +154,7 @@ public class UserListFragment extends ListFragment implements ListClickListener,
@Override
public boolean onPlaceholderClick(long cursor) {
if (listTask != null && listTask.idle()) {
if (listTask != null && listTask.isIdle()) {
load(cursor);
return true;
}
@ -163,12 +163,12 @@ public class UserListFragment extends ListFragment implements ListClickListener,
@Override
public void onResult(UserlistResult res) {
public void onResult(UserlistResult result) {
setRefresh(false);
if (res.userlists != null) {
adapter.addItems(res.userlists);
if (result.userlists != null) {
adapter.addItems(result.userlists);
} else {
String message = ErrorHandler.getErrorMessage(requireContext(), res.exception);
String message = ErrorHandler.getErrorMessage(requireContext(), result.exception);
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show();
adapter.disableLoading();
}