fixed alert dialogs, added cursor system for lists

This commit is contained in:
nuclearfog 2020-10-22 10:53:10 +02:00
parent 39c5945222
commit 75adacf800
No known key found for this signature in database
GPG Key ID: D5490E4A81F97B14
8 changed files with 282 additions and 134 deletions

View File

@ -1,5 +1,6 @@
package org.nuclearfog.twidda.activity; package org.nuclearfog.twidda.activity;
import android.app.Dialog;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@ -23,6 +24,7 @@ import org.nuclearfog.twidda.backend.utils.ErrorHandler;
import org.nuclearfog.twidda.backend.utils.FontTool; import org.nuclearfog.twidda.backend.utils.FontTool;
import org.nuclearfog.twidda.database.GlobalSettings; import org.nuclearfog.twidda.database.GlobalSettings;
import static android.content.DialogInterface.BUTTON_POSITIVE;
import static android.os.AsyncTask.Status.RUNNING; import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.INVISIBLE; import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
@ -36,7 +38,7 @@ import static org.nuclearfog.twidda.activity.TwitterList.RET_LIST_CREATED;
/** /**
* Popup activity for the list editor * Popup activity for the list editor
*/ */
public class ListPopup extends AppCompatActivity implements OnClickListener { public class ListPopup extends AppCompatActivity implements OnClickListener, DialogInterface.OnClickListener {
/** /**
* Key for the list ID of the list if an existing list should be updated * Key for the list ID of the list if an existing list should be updated
@ -62,6 +64,7 @@ public class ListPopup extends AppCompatActivity implements OnClickListener {
private EditText titleInput, subTitleInput; private EditText titleInput, subTitleInput;
private CompoundButton visibility; private CompoundButton visibility;
private View progressCircle; private View progressCircle;
private Dialog leaveDialog;
private long listId = -1; private long listId = -1;
private String title = ""; private String title = "";
@ -108,16 +111,15 @@ public class ListPopup extends AppCompatActivity implements OnClickListener {
&& subTitleInput.getText().toString().equals(description)) { && subTitleInput.getText().toString().equals(description)) {
super.onBackPressed(); super.onBackPressed();
} else { } else {
Builder alertDialog = new Builder(this, R.style.ConfirmDialog); if (leaveDialog == null) {
alertDialog.setMessage(R.string.confirm_discard); Builder builder = new Builder(this, R.style.ConfirmDialog);
alertDialog.setNegativeButton(R.string.confirm_no, null); builder.setMessage(R.string.confirm_discard);
alertDialog.setPositiveButton(R.string.confirm_yes, new DialogInterface.OnClickListener() { builder.setNegativeButton(R.string.confirm_no, null);
@Override builder.setPositiveButton(R.string.confirm_yes, this);
public void onClick(DialogInterface dialog, int which) { leaveDialog = builder.show();
finish(); } else if (!leaveDialog.isShowing()) {
} leaveDialog.show();
}); }
alertDialog.show();
} }
} }
@ -145,6 +147,14 @@ public class ListPopup extends AppCompatActivity implements OnClickListener {
} }
} }
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == BUTTON_POSITIVE && dialog == leaveDialog) {
finish();
}
}
/** /**
* called when an update starts * called when an update starts
*/ */

View File

@ -1,5 +1,6 @@
package org.nuclearfog.twidda.activity; package org.nuclearfog.twidda.activity;
import android.app.Dialog;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.DialogInterface; import android.content.DialogInterface;
@ -43,6 +44,7 @@ import java.text.NumberFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static android.content.DialogInterface.BUTTON_POSITIVE;
import static android.os.AsyncTask.Status.RUNNING; import static android.os.AsyncTask.Status.RUNNING;
import static android.view.View.GONE; import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
@ -65,7 +67,7 @@ import static org.nuclearfog.twidda.fragment.TweetFragment.RETURN_TWEET_CHANGED;
* Tweet Activity for tweet and user informations * Tweet Activity for tweet and user informations
*/ */
public class TweetActivity extends AppCompatActivity implements OnClickListener, public class TweetActivity extends AppCompatActivity implements OnClickListener,
OnLongClickListener, OnTagClickListener { OnLongClickListener, OnTagClickListener, DialogInterface.OnClickListener {
/** /**
* ID of the tweet to open. required * ID of the tweet to open. required
@ -86,6 +88,7 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
private Button rtwButton, favButton, replyName, tweetLocGPS; private Button rtwButton, favButton, replyName, tweetLocGPS;
private ImageView profile_img, mediaButton; private ImageView profile_img, mediaButton;
private View header, footer, sensitive_media; private View header, footer, sensitive_media;
private Dialog deleteDialog;
private FragmentAdapter adapter; private FragmentAdapter adapter;
private GlobalSettings settings; private GlobalSettings settings;
@ -188,17 +191,16 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
if (statusAsync != null && tweet != null && statusAsync.getStatus() != RUNNING) { if (statusAsync != null && tweet != null && statusAsync.getStatus() != RUNNING) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.delete_tweet: case R.id.delete_tweet:
Builder deleteDialog = new Builder(this, R.style.ConfirmDialog); if (deleteDialog == null) {
deleteDialog.setMessage(R.string.confirm_delete_tweet); Builder builder = new Builder(this, R.style.ConfirmDialog);
deleteDialog.setPositiveButton(R.string.confirm_yes, new DialogInterface.OnClickListener() { builder.setMessage(R.string.confirm_delete_tweet);
@Override builder.setPositiveButton(R.string.confirm_yes, this);
public void onClick(DialogInterface dialog, int which) { builder.setNegativeButton(R.string.confirm_no, null);
statusAsync = new TweetLoader(TweetActivity.this, Action.DELETE); deleteDialog = builder.create();
statusAsync.execute(tweet.getId()); }
} if (!deleteDialog.isShowing()) {
}); deleteDialog.show();
deleteDialog.setNegativeButton(R.string.confirm_no, null); }
deleteDialog.show();
break; break;
case R.id.tweet_link: case R.id.tweet_link:
@ -229,6 +231,15 @@ public class TweetActivity extends AppCompatActivity implements OnClickListener,
} }
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == BUTTON_POSITIVE && dialog == deleteDialog && tweet != null) {
statusAsync = new TweetLoader(TweetActivity.this, Action.DELETE);
statusAsync.execute(tweet.getId());
}
}
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if (statusAsync != null && tweet != null && statusAsync.getStatus() != RUNNING) { if (statusAsync != null && tweet != null && statusAsync.getStatus() != RUNNING) {

View File

@ -20,7 +20,6 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AlertDialog.Builder; import androidx.appcompat.app.AlertDialog.Builder;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
@ -37,6 +36,7 @@ import java.util.List;
import static android.Manifest.permission.ACCESS_FINE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.content.DialogInterface.BUTTON_POSITIVE;
import static android.content.Intent.ACTION_PICK; import static android.content.Intent.ACTION_PICK;
import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.AsyncTask.Status.RUNNING; import static android.os.AsyncTask.Status.RUNNING;
@ -55,7 +55,8 @@ import static org.nuclearfog.twidda.activity.MediaViewer.MEDIAVIEWER_VIDEO;
/** /**
* Activity to create a tweet * Activity to create a tweet
*/ */
public class TweetPopup extends AppCompatActivity implements OnClickListener, LocationListener, OnDismissListener { public class TweetPopup extends AppCompatActivity implements OnClickListener, LocationListener,
OnDismissListener, DialogInterface.OnClickListener {
/** /**
* key for the replied tweet if any * key for the replied tweet if any
@ -90,12 +91,13 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
private List<String> mediaPath; private List<String> mediaPath;
private ImageButton mediaBtn, previewBtn, locationBtn; private ImageButton mediaBtn, previewBtn, locationBtn;
private View locationProg; private View locationProg;
private Dialog loadingCircle; private Dialog loadingCircle, errorDialog, closingDialog;
private EditText tweetText; private EditText tweetText;
private MediaType selectedFormat = MediaType.NONE; private MediaType selectedFormat = MediaType.NONE;
private String prefix = ""; private String prefix = "";
private long inReplyId = 0; private long inReplyId = 0;
private TweetHolder tweet;
@Override @Override
protected void onCreate(@Nullable Bundle b) { protected void onCreate(@Nullable Bundle b) {
@ -244,15 +246,15 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
if (tweetStr.trim().isEmpty() && mediaPath.isEmpty()) { if (tweetStr.trim().isEmpty() && mediaPath.isEmpty()) {
Toast.makeText(this, R.string.error_empty_tweet, LENGTH_SHORT).show(); Toast.makeText(this, R.string.error_empty_tweet, LENGTH_SHORT).show();
} else if (locationProg.getVisibility() == INVISIBLE) { } else if (locationProg.getVisibility() == INVISIBLE) {
TweetHolder tweet = new TweetHolder(tweetStr, inReplyId); tweet = new TweetHolder(tweetStr, inReplyId);
if (selectedFormat == MediaType.IMAGE || selectedFormat == MediaType.GIF) if (selectedFormat == MediaType.IMAGE || selectedFormat == MediaType.GIF)
tweet.addMedia(mediaPath.toArray(new String[0]), TweetHolder.MediaType.IMAGE); tweet.addMedia(mediaPath.toArray(new String[0]), TweetHolder.MediaType.IMAGE);
else if (selectedFormat == MediaType.VIDEO) else if (selectedFormat == MediaType.VIDEO)
tweet.addMedia(mediaPath.toArray(new String[0]), TweetHolder.MediaType.VIDEO); tweet.addMedia(mediaPath.toArray(new String[0]), TweetHolder.MediaType.VIDEO);
if (location != null) if (location != null)
tweet.addLocation(location); tweet.addLocation(location);
uploaderAsync = new TweetUploader(this, tweet); uploaderAsync = new TweetUploader(this);
uploaderAsync.execute(); uploaderAsync.execute(tweet);
} }
break; break;
@ -325,6 +327,19 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
} }
} }
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == BUTTON_POSITIVE) {
if (dialog == errorDialog) {
uploaderAsync = new TweetUploader(this);
uploaderAsync.execute(tweet);
} else if (dialog == closingDialog) {
finish();
}
}
}
/** /**
* enable or disable loading dialog * enable or disable loading dialog
* *
@ -348,21 +363,18 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
/** /**
* Show confirmation dialog if an error occurs while sending tweet * Show confirmation dialog if an error occurs while sending tweet
*
* @param tweet tweet to re-send
*/ */
public void onError(final TweetHolder tweet, EngineException error) { public void onError(EngineException error) {
ErrorHandler.handleFailure(this, error); ErrorHandler.handleFailure(this, error);
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.ConfirmDialog); if (errorDialog == null) {
builder.setTitle(R.string.info_error).setMessage(R.string.error_sending_tweet) Builder builder = new Builder(this, R.style.ConfirmDialog);
.setPositiveButton(R.string.confirm_retry, new DialogInterface.OnClickListener() { builder.setTitle(R.string.info_error).setMessage(R.string.error_sending_tweet);
@Override builder.setPositiveButton(R.string.confirm_retry, this);
public void onClick(DialogInterface dialog, int which) { builder.setNegativeButton(android.R.string.cancel, null);
uploaderAsync = new TweetUploader(TweetPopup.this, tweet); errorDialog = builder.show();
uploaderAsync.execute(); } else if (!errorDialog.isShowing()) {
} errorDialog.show();
}) }
.setNegativeButton(android.R.string.cancel, null).show();
} }
@ -371,16 +383,15 @@ public class TweetPopup extends AppCompatActivity implements OnClickListener, Lo
*/ */
private void showClosingMsg() { private void showClosingMsg() {
if (!prefix.equals(tweetText.getText().toString()) || !mediaPath.isEmpty()) { if (!prefix.equals(tweetText.getText().toString()) || !mediaPath.isEmpty()) {
Builder closeDialog = new Builder(this, R.style.ConfirmDialog); if (closingDialog == null) {
closeDialog.setMessage(R.string.confirm_cancel_tweet); Builder builder = new Builder(this, R.style.ConfirmDialog);
closeDialog.setNegativeButton(R.string.confirm_no, null); builder.setMessage(R.string.confirm_cancel_tweet);
closeDialog.setPositiveButton(R.string.confirm_yes, new DialogInterface.OnClickListener() { builder.setNegativeButton(R.string.confirm_no, null);
@Override builder.setPositiveButton(R.string.confirm_yes, this);
public void onClick(DialogInterface dialog, int which) { closingDialog = builder.show();
finish(); } else if (!closingDialog.isShowing()) {
} closingDialog.show();
}); }
closeDialog.show();
} else { } else {
finish(); finish();
} }

View File

@ -13,27 +13,25 @@ import java.lang.ref.WeakReference;
/** /**
* Background task for uploading tweet * Background task for uploading tweet
*
* @see TweetPopup * @see TweetPopup
*/ */
public class TweetUploader extends AsyncTask<Void, Void, Boolean> { public class TweetUploader extends AsyncTask<TweetHolder, Void, Boolean> {
@Nullable @Nullable
private EngineException twException; private EngineException twException;
private WeakReference<TweetPopup> callback; private final WeakReference<TweetPopup> callback;
private TwitterEngine mTwitter; private final TwitterEngine mTwitter;
private TweetHolder tweet;
/** /**
* initialize task * initialize task
* *
* @param callback Activity context * @param callback Activity context
* @param tweet tweet information
*/ */
public TweetUploader(TweetPopup callback, TweetHolder tweet) { public TweetUploader(TweetPopup callback) {
super(); super();
this.callback = new WeakReference<>(callback); this.callback = new WeakReference<>(callback);
mTwitter = TwitterEngine.getInstance(callback); mTwitter = TwitterEngine.getInstance(callback);
this.tweet = tweet;
} }
@ -46,8 +44,9 @@ public class TweetUploader extends AsyncTask<Void, Void, Boolean> {
@Override @Override
protected Boolean doInBackground(Void[] v) { protected Boolean doInBackground(TweetHolder[] param) {
try { try {
TweetHolder tweet = param[0];
mTwitter.uploadStatus(tweet); mTwitter.uploadStatus(tweet);
return true; return true;
} catch (EngineException twException) { } catch (EngineException twException) {
@ -66,7 +65,7 @@ public class TweetUploader extends AsyncTask<Void, Void, Boolean> {
if (success) { if (success) {
callback.get().onSuccess(); callback.get().onSuccess();
} else if (twException != null) { } else if (twException != null) {
callback.get().onError(tweet, twException); callback.get().onError(twException);
} }
} }
} }

View File

@ -6,11 +6,11 @@ import androidx.annotation.Nullable;
import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.engine.EngineException;
import org.nuclearfog.twidda.backend.engine.TwitterEngine; import org.nuclearfog.twidda.backend.engine.TwitterEngine;
import org.nuclearfog.twidda.backend.holder.UserListList;
import org.nuclearfog.twidda.backend.items.TwitterList; import org.nuclearfog.twidda.backend.items.TwitterList;
import org.nuclearfog.twidda.fragment.ListFragment; import org.nuclearfog.twidda.fragment.ListFragment;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.List;
/** /**
@ -18,7 +18,9 @@ import java.util.List;
* *
* @see ListFragment * @see ListFragment
*/ */
public class TwitterListLoader extends AsyncTask<Object, TwitterList, List<TwitterList>> { public class TwitterListLoader extends AsyncTask<Long, Void, UserListList> {
public static final long NO_CURSOR = -1;
public enum Action { public enum Action {
LOAD, LOAD,
@ -32,39 +34,37 @@ public class TwitterListLoader extends AsyncTask<Object, TwitterList, List<Twitt
private final TwitterEngine mTwitter; private final TwitterEngine mTwitter;
private final Action action; private final Action action;
private final long id;
private final String ownerName;
public TwitterListLoader(ListFragment callback, Action action) {
public TwitterListLoader(ListFragment callback, Action action, long id, String ownerName) {
super(); super();
mTwitter = TwitterEngine.getInstance(callback.getContext()); mTwitter = TwitterEngine.getInstance(callback.getContext());
this.callback = new WeakReference<>(callback); this.callback = new WeakReference<>(callback);
this.action = action; this.action = action;
this.ownerName = ownerName;
this.id = id;
} }
@Override @Override
protected List<TwitterList> doInBackground(Object[] param) { protected UserListList doInBackground(Long[] param) {
try { try {
switch (action) { switch (action) {
case LOAD: case LOAD:
if (param[0] instanceof Long) { long cursor = param[0];
long ownerId = (long) param[0]; if (id > 0) {
return mTwitter.getUserList(ownerId); return mTwitter.getUserList(id, cursor);
} else { } else {
String ownerName = (String) param[0]; return mTwitter.getUserList(ownerName, cursor);
return mTwitter.getUserList(ownerName);
} }
case FOLLOW: case FOLLOW:
long listId = (long) param[0]; return new UserListList(mTwitter.followUserList(id));
TwitterList result = mTwitter.followUserList(listId);
publishProgress(result);
break;
case DELETE: case DELETE:
listId = (long) param[0]; return new UserListList(mTwitter.deleteUserList(id));
TwitterList deletedList = mTwitter.deleteUserList(listId);
publishProgress(deletedList);
break;
} }
} catch (EngineException twException) { } catch (EngineException twException) {
this.twException = twException; this.twException = twException;
@ -76,23 +76,24 @@ public class TwitterListLoader extends AsyncTask<Object, TwitterList, List<Twitt
@Override @Override
protected void onProgressUpdate(TwitterList[] lists) { protected void onPostExecute(UserListList result) {
TwitterList list = lists[0];
if (callback.get() != null) {
if (action == Action.FOLLOW) {
callback.get().updateItem(list);
} else if (action == Action.DELETE) {
callback.get().removeItem(list.getId());
}
}
}
@Override
protected void onPostExecute(List<TwitterList> result) {
if (callback.get() != null) { if (callback.get() != null) {
if (result != null) { if (result != null) {
callback.get().setData(result); switch (action) {
case LOAD:
callback.get().setData(result);
break;
case FOLLOW:
TwitterList list = result.get(0);
callback.get().updateItem(list);
break;
case DELETE:
long id = result.get(0).getId();
callback.get().removeItem(id);
break;
}
} else { } else {
callback.get().onError(twException); callback.get().onError(twException);
} }

View File

@ -12,6 +12,7 @@ import org.nuclearfog.twidda.backend.holder.MessageHolder;
import org.nuclearfog.twidda.backend.holder.TweetHolder; import org.nuclearfog.twidda.backend.holder.TweetHolder;
import org.nuclearfog.twidda.backend.holder.TwitterUserList; import org.nuclearfog.twidda.backend.holder.TwitterUserList;
import org.nuclearfog.twidda.backend.holder.UserHolder; import org.nuclearfog.twidda.backend.holder.UserHolder;
import org.nuclearfog.twidda.backend.holder.UserListList;
import org.nuclearfog.twidda.backend.items.Message; import org.nuclearfog.twidda.backend.items.Message;
import org.nuclearfog.twidda.backend.items.TrendLocation; import org.nuclearfog.twidda.backend.items.TrendLocation;
import org.nuclearfog.twidda.backend.items.Tweet; import org.nuclearfog.twidda.backend.items.Tweet;
@ -903,13 +904,16 @@ public class TwitterEngine {
* get user list * get user list
* *
* @param userId id of the list owner * @param userId id of the list owner
* @param cursor list cursor to set the start point
* @return list information * @return list information
* @throws EngineException if access is unavailable * @throws EngineException if access is unavailable
*/ */
public List<TwitterList> getUserList(long userId) throws EngineException { public UserListList getUserList(long userId, long cursor) throws EngineException {
try { try {
List<TwitterList> result = new LinkedList<>(); // TODO add a paging system
List<UserList> lists = twitter.getUserLists(userId); List<UserList> lists = twitter.getUserLists(userId);
long prevCursor = cursor > 0 ? cursor : 0;
long nextCursor = 0;
UserListList result = new UserListList(0, 0); // todo add paging system
for (UserList list : lists) for (UserList list : lists)
result.add(new TwitterList(list, twitterID)); result.add(new TwitterList(list, twitterID));
return result; return result;
@ -923,13 +927,16 @@ public class TwitterEngine {
* get user list * get user list
* *
* @param username id of the list owner * @param username id of the list owner
* @param cursor list cursor to set the start point
* @return list information * @return list information
* @throws EngineException if access is unavailable * @throws EngineException if access is unavailable
*/ */
public List<TwitterList> getUserList(String username) throws EngineException { public UserListList getUserList(String username, long cursor) throws EngineException {
try { try {
List<TwitterList> result = new LinkedList<>();
List<UserList> lists = twitter.getUserLists(username); List<UserList> lists = twitter.getUserLists(username);
long prevCursor = cursor > 0 ? cursor : 0;
long nextCursor = 0;
UserListList result = new UserListList(prevCursor, nextCursor); // todo add paging system
for (UserList list : lists) for (UserList list : lists)
result.add(new TwitterList(list, twitterID)); result.add(new TwitterList(list, twitterID));
return result; return result;
@ -938,6 +945,28 @@ public class TwitterEngine {
} }
} }
/**
* get the lists the user has been added to
*
* @param userId ID of the user
* @param cursor list cursor
* @return a list of user lists
* @throws EngineException if access is unavailable
*/
public UserListList getUserListMemberships(long userId, long cursor) throws EngineException {
try {
int count = settings.getListSize();
PagableResponseList<UserList> lists = twitter.getUserListMemberships(userId, count, cursor);
long prevCursor = cursor > 0 ? cursor : 0;
long nextCursor = lists.getNextCursor();
UserListList result = new UserListList(prevCursor, nextCursor);
for (UserList list : lists)
result.add(new TwitterList(list, twitterID));
return result;
} catch (TwitterException err) {
throw new EngineException(err);
}
}
/** /**
* Follow action for twitter list * Follow action for twitter list

View File

@ -0,0 +1,68 @@
package org.nuclearfog.twidda.backend.holder;
import androidx.annotation.NonNull;
import org.nuclearfog.twidda.backend.items.TwitterList;
import java.util.LinkedList;
/**
* Container class for user lists containing extra cursors for paging
*/
public class UserListList extends LinkedList<TwitterList> {
private long prevCursor = 0;
private long nextCursor = 0;
/**
* @param list single list item
*/
public UserListList(TwitterList list) {
super();
add(list);
}
/**
* @param prevCursor previous list cursor or 0 if list starts
* @param nextCursor next cursor or 0 if list ends
*/
public UserListList(long prevCursor, long nextCursor) {
super();
this.prevCursor = prevCursor;
this.nextCursor = nextCursor;
}
/**
* check if list is linked to a previous list
*
* @return true if list is linked
*/
public boolean hasPrevious() {
return prevCursor != 0;
}
/**
* check if list has a successor
*
* @return true if list has a successor
*/
public boolean hasNext() {
return nextCursor != 0;
}
/**
* get next link to a list
*
* @return cursor
*/
public long getNext() {
return nextCursor;
}
@Override
@NonNull
public String toString() {
return "size=" + size() + " pre=" + prevCursor + " pos=" + nextCursor;
}
}

View File

@ -1,5 +1,6 @@
package org.nuclearfog.twidda.fragment; package org.nuclearfog.twidda.fragment;
import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@ -32,6 +33,7 @@ import org.nuclearfog.twidda.database.GlobalSettings;
import java.util.List; import java.util.List;
import static android.content.DialogInterface.BUTTON_POSITIVE;
import static android.os.AsyncTask.Status.FINISHED; import static android.os.AsyncTask.Status.FINISHED;
import static android.os.AsyncTask.Status.RUNNING; import static android.os.AsyncTask.Status.RUNNING;
import static org.nuclearfog.twidda.activity.ListDetail.KEY_CURRENT_USER_OWNS; import static org.nuclearfog.twidda.activity.ListDetail.KEY_CURRENT_USER_OWNS;
@ -46,11 +48,13 @@ import static org.nuclearfog.twidda.activity.UserProfile.KEY_PROFILE_ID;
import static org.nuclearfog.twidda.backend.TwitterListLoader.Action.DELETE; import static org.nuclearfog.twidda.backend.TwitterListLoader.Action.DELETE;
import static org.nuclearfog.twidda.backend.TwitterListLoader.Action.FOLLOW; import static org.nuclearfog.twidda.backend.TwitterListLoader.Action.FOLLOW;
import static org.nuclearfog.twidda.backend.TwitterListLoader.Action.LOAD; import static org.nuclearfog.twidda.backend.TwitterListLoader.Action.LOAD;
import static org.nuclearfog.twidda.backend.TwitterListLoader.NO_CURSOR;
/** /**
* Fragment class for user lists * Fragment class for user lists
*/ */
public class ListFragment extends Fragment implements OnRefreshListener, ListClickListener, FragmentChangeObserver { public class ListFragment extends Fragment implements OnRefreshListener, ListClickListener,
FragmentChangeObserver, DialogInterface.OnClickListener {
/** /**
* Key for the owner ID * Key for the owner ID
@ -69,6 +73,10 @@ public class ListFragment extends Fragment implements OnRefreshListener, ListCli
private RecyclerView list; private RecyclerView list;
private ListAdapter adapter; private ListAdapter adapter;
private Dialog followDialog, deleteDialog;
private long selectedList;
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle param) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle param) {
Context context = inflater.getContext(); Context context = inflater.getContext();
@ -94,7 +102,7 @@ public class ListFragment extends Fragment implements OnRefreshListener, ListCli
super.onStart(); super.onStart();
if (listTask == null) { if (listTask == null) {
setRefresh(true); setRefresh(true);
load(); load(NO_CURSOR);
} }
} }
@ -110,7 +118,7 @@ public class ListFragment extends Fragment implements OnRefreshListener, ListCli
@Override @Override
public void onRefresh() { public void onRefresh() {
if (listTask != null && listTask.getStatus() != RUNNING) { if (listTask != null && listTask.getStatus() != RUNNING) {
load(); load(NO_CURSOR);
} }
} }
@ -127,19 +135,19 @@ public class ListFragment extends Fragment implements OnRefreshListener, ListCli
case FOLLOW: case FOLLOW:
if (listItem.isFollowing()) { if (listItem.isFollowing()) {
Builder confirmDialog = new Builder(getContext(), R.style.ConfirmDialog); if (followDialog == null) {
confirmDialog.setMessage(R.string.confirm_unfollow_list); Builder confirmDialog = new Builder(getContext(), R.style.ConfirmDialog);
confirmDialog.setNegativeButton(R.string.confirm_no, null); confirmDialog.setMessage(R.string.confirm_unfollow_list);
confirmDialog.setPositiveButton(R.string.confirm_yes, new DialogInterface.OnClickListener() { confirmDialog.setNegativeButton(R.string.confirm_no, null);
@Override confirmDialog.setPositiveButton(R.string.confirm_yes, this);
public void onClick(DialogInterface dialog, int which) { followDialog = confirmDialog.create();
listTask = new TwitterListLoader(ListFragment.this, FOLLOW); }
listTask.execute(listItem.getId()); if (!followDialog.isShowing()) {
} selectedList = listItem.getId();
}); followDialog.show();
confirmDialog.show(); }
} else { } else {
listTask = new TwitterListLoader(this, FOLLOW); listTask = new TwitterListLoader(this, FOLLOW, listItem.getId(), "");
listTask.execute(listItem.getId()); listTask.execute(listItem.getId());
} }
break; break;
@ -164,29 +172,43 @@ public class ListFragment extends Fragment implements OnRefreshListener, ListCli
break; break;
case DELETE: case DELETE:
Builder confirmDialog = new Builder(getContext(), R.style.ConfirmDialog); if (deleteDialog == null) {
confirmDialog.setMessage(R.string.confirm_delete_list); Builder confirmDialog = new Builder(requireContext(), R.style.ConfirmDialog);
confirmDialog.setNegativeButton(R.string.confirm_no, null); confirmDialog.setMessage(R.string.confirm_delete_list);
confirmDialog.setPositiveButton(R.string.confirm_yes, new DialogInterface.OnClickListener() { confirmDialog.setNegativeButton(R.string.confirm_no, null);
@Override confirmDialog.setPositiveButton(R.string.confirm_yes, this);
public void onClick(DialogInterface dialog, int which) { deleteDialog = confirmDialog.create();
listTask = new TwitterListLoader(ListFragment.this, DELETE); }
listTask.execute(listItem.getId()); if (!deleteDialog.isShowing()) {
} selectedList = listItem.getId();
}); deleteDialog.show();
confirmDialog.show(); }
break; break;
} }
} }
} }
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == BUTTON_POSITIVE) {
if (dialog == followDialog) {
listTask = new TwitterListLoader(this, FOLLOW, selectedList, "");
listTask.execute();
} else if (dialog == deleteDialog) {
listTask = new TwitterListLoader(this, DELETE, selectedList, "");
listTask.execute();
}
}
}
@Override @Override
public void onReset() { public void onReset() {
if (list != null) { if (list != null) {
list.setAdapter(adapter); list.setAdapter(adapter);
setRefresh(true); setRefresh(true);
load(); load(NO_CURSOR);
} }
} }
@ -225,9 +247,10 @@ public class ListFragment extends Fragment implements OnRefreshListener, ListCli
/** /**
* called from {@link TwitterListLoader} to enable or disable RefreshLayout * called from {@link TwitterListLoader} to enable or disable RefreshLayout
*
* @param enable true to enable RefreshLayout with delay * @param enable true to enable RefreshLayout with delay
*/ */
public void setRefresh(boolean enable) { private void setRefresh(boolean enable) {
if (enable) { if (enable) {
reloadLayout.postDelayed(new Runnable() { reloadLayout.postDelayed(new Runnable() {
@Override @Override
@ -256,17 +279,13 @@ public class ListFragment extends Fragment implements OnRefreshListener, ListCli
/** /**
* load content into the list * load content into the list
*/ */
private void load() { private void load(long cursor) {
Bundle param = getArguments(); Bundle param = getArguments();
if (param != null) { if (param != null) {
listTask = new TwitterListLoader(this, LOAD); long id = param.getLong(KEY_FRAG_LIST_OWNER_ID, 0);
if (param.containsKey(KEY_FRAG_LIST_OWNER_ID)) { String ownerName = param.getString(KEY_FRAG_LIST_OWNER_NAME, "");
long ownerId = param.getLong(KEY_FRAG_LIST_OWNER_ID); listTask = new TwitterListLoader(this, LOAD, id, ownerName);
listTask.execute(ownerId); listTask.execute(cursor);
} else if (param.containsKey(KEY_FRAG_LIST_OWNER_NAME)) {
String ownerName = param.getString(KEY_FRAG_LIST_OWNER_NAME);
listTask.execute(ownerName);
}
} }
} }
} }