diff --git a/app/src/main/java/org/nuclearfog/twidda/activity/ListDetail.java b/app/src/main/java/org/nuclearfog/twidda/activity/ListDetail.java index f7ce9311..9c86c318 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activity/ListDetail.java +++ b/app/src/main/java/org/nuclearfog/twidda/activity/ListDetail.java @@ -26,7 +26,7 @@ import org.nuclearfog.twidda.backend.ListAction; import org.nuclearfog.twidda.backend.ListManager; import org.nuclearfog.twidda.backend.ListManager.ListManagerCallback; import org.nuclearfog.twidda.backend.engine.EngineException; -import org.nuclearfog.twidda.backend.items.UserList; +import org.nuclearfog.twidda.backend.items.TwitterList; import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.backend.utils.DialogBuilder; import org.nuclearfog.twidda.backend.utils.DialogBuilder.OnDialogClick; @@ -91,7 +91,7 @@ public class ListDetail extends AppCompatActivity implements OnTabSelectedListen private Dialog unfollowDialog, deleteDialog; @Nullable - private UserList userList; + private TwitterList userList; private long listId = -1; @Override @@ -114,8 +114,8 @@ public class ListDetail extends AppCompatActivity implements OnTabSelectedListen unfollowDialog = DialogBuilder.create(this, LIST_UNFOLLOW, this); Object data = getIntent().getSerializableExtra(KEY_LIST_DATA); - if (data instanceof UserList) { - userList = (UserList) data; + if (data instanceof TwitterList) { + userList = (TwitterList) data; listId = userList.getId(); toolbar.setTitle(userList.getTitle()); toolbar.setSubtitle(userList.getDescription()); @@ -228,8 +228,8 @@ public class ListDetail extends AppCompatActivity implements OnTabSelectedListen if (result != null && reqCode == REQ_LIST_CHANGE) { if (returnCode == RET_LIST_CHANGED) { Object data = result.getSerializableExtra(RET_LIST_DATA); - if (data instanceof UserList) { - userList = (UserList) data; + if (data instanceof TwitterList) { + userList = (TwitterList) data; toolbar.setTitle(userList.getTitle()); toolbar.setSubtitle(userList.getDescription()); invalidateOptionsMenu(); @@ -312,9 +312,9 @@ public class ListDetail extends AppCompatActivity implements OnTabSelectedListen /** * called from {@link ListAction} to update userlist information * - * @param userList UserList information + * @param userList TwitterList information */ - public void onSuccess(UserList userList, ListAction.Action action) { + public void onSuccess(TwitterList userList, ListAction.Action action) { this.userList = userList; switch (action) { case LOAD: diff --git a/app/src/main/java/org/nuclearfog/twidda/activity/ListEditor.java b/app/src/main/java/org/nuclearfog/twidda/activity/ListEditor.java index c25175f4..a7ba3fae 100644 --- a/app/src/main/java/org/nuclearfog/twidda/activity/ListEditor.java +++ b/app/src/main/java/org/nuclearfog/twidda/activity/ListEditor.java @@ -20,7 +20,7 @@ import org.nuclearfog.twidda.R; import org.nuclearfog.twidda.backend.ListUpdater; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.holder.ListHolder; -import org.nuclearfog.twidda.backend.items.UserList; +import org.nuclearfog.twidda.backend.items.TwitterList; import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.backend.utils.DialogBuilder; import org.nuclearfog.twidda.backend.utils.DialogBuilder.OnDialogClick; @@ -52,7 +52,7 @@ public class ListEditor extends AppCompatActivity implements OnClickListener, On private Dialog leaveDialog, loadingCircle; private AlertDialog errorDialog; @Nullable - private UserList userList; + private TwitterList userList; @Override protected void onCreate(Bundle b) { @@ -73,8 +73,8 @@ public class ListEditor extends AppCompatActivity implements OnClickListener, On AppStyles.setEditorTheme(settings, root, background); Object data = getIntent().getSerializableExtra(KEY_LIST_EDITOR_DATA); - if (data instanceof UserList) { - userList = (UserList) data; + if (data instanceof TwitterList) { + userList = (TwitterList) data; titleInput.setText(userList.getTitle()); subTitleInput.setText(userList.getDescription()); visibility.setChecked(!userList.isPrivate()); @@ -146,7 +146,7 @@ public class ListEditor extends AppCompatActivity implements OnClickListener, On /** * called when a list was updated successfully */ - public void onSuccess(UserList result) { + public void onSuccess(TwitterList result) { if (userList != null) { Toast.makeText(this, R.string.info_list_updated, Toast.LENGTH_SHORT).show(); Intent data = new Intent(); diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java b/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java index 92c20798..ab5d2237 100644 --- a/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/ImageAdapter.java @@ -5,9 +5,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.ProgressBar; import androidx.annotation.MainThread; import androidx.annotation.NonNull; @@ -15,8 +12,9 @@ import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.adapter.holder.Footer; +import org.nuclearfog.twidda.adapter.holder.ImageItem; import org.nuclearfog.twidda.backend.holder.ImageHolder; -import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.database.GlobalSettings; import java.util.LinkedList; @@ -49,7 +47,10 @@ public class ImageAdapter extends Adapter { private boolean loading = false; private boolean saveImg = true; - + /** + * @param settings App settings to set theme + * @param itemClickListener click listener + */ public ImageAdapter(GlobalSettings settings, OnImageClickListener itemClickListener) { this.itemClickListener = itemClickListener; this.settings = settings; @@ -145,7 +146,9 @@ public class ImageAdapter extends Adapter { return item; } else { View view = inflater.inflate(R.layout.item_image_load, parent, false); - return new LoadItem(view, settings.getHighlightColor()); + Footer footer = new Footer(view, settings); + footer.loadBtn.setVisibility(View.INVISIBLE); + return footer; } } @@ -160,35 +163,8 @@ public class ImageAdapter extends Adapter { } /** - * Holder for image + * click listener for image items */ - private final class ImageItem extends ViewHolder { - final ImageView preview; - final ImageButton saveButton; - - ImageItem(View view, GlobalSettings settings) { - super(view); - preview = view.findViewById(R.id.item_image_preview); - saveButton = view.findViewById(R.id.item_image_save); - saveButton.setImageResource(R.drawable.save); - AppStyles.setButtonColor(saveButton, settings.getFontColor()); - AppStyles.setDrawableColor(saveButton, settings.getIconColor()); - } - } - - /** - * Holder for progress circle - */ - private final class LoadItem extends ViewHolder { - - LoadItem(View v, int color) { - super(v); - ProgressBar progress = v.findViewById(R.id.imageitem_progress); - AppStyles.setProgressColor(progress, color); - } - } - - public interface OnImageClickListener { /** diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/ListAdapter.java b/app/src/main/java/org/nuclearfog/twidda/adapter/ListAdapter.java index 53bfe52d..8d22cf7e 100644 --- a/app/src/main/java/org/nuclearfog/twidda/adapter/ListAdapter.java +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/ListAdapter.java @@ -4,24 +4,20 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.MainThread; import androidx.annotation.NonNull; -import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.squareup.picasso.Picasso; import org.nuclearfog.twidda.R; -import org.nuclearfog.twidda.backend.holder.UserListList; +import org.nuclearfog.twidda.adapter.holder.Footer; +import org.nuclearfog.twidda.adapter.holder.ListHolder; +import org.nuclearfog.twidda.backend.items.TwitterList; import org.nuclearfog.twidda.backend.items.User; -import org.nuclearfog.twidda.backend.items.UserList; -import org.nuclearfog.twidda.backend.utils.AppStyles; +import org.nuclearfog.twidda.backend.lists.UserLists; import org.nuclearfog.twidda.database.GlobalSettings; import org.nuclearfog.twidda.fragment.UserListFragment; @@ -29,7 +25,6 @@ import java.text.NumberFormat; import jp.wasabeef.picasso.transformations.RoundedCornersTransformation; -import static android.graphics.PorterDuff.Mode.SRC_IN; import static android.view.View.GONE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; @@ -63,7 +58,7 @@ public class ListAdapter extends Adapter { private GlobalSettings settings; private NumberFormat formatter = NumberFormat.getIntegerInstance(); - private UserListList data = new UserListList(); + private UserLists data = new UserLists(); private int loadingIndex = NO_LOADING; @@ -78,11 +73,13 @@ public class ListAdapter extends Adapter { * @param newData new list to add */ @MainThread - public void setData(UserListList newData) { + public void setData(UserLists newData) { if (newData.isEmpty()) { if (!data.isEmpty() && data.peekLast() == null) { // remove footer - data.pollLast(); + int end = data.size() - 1; + data.remove(end); + notifyItemRemoved(end); } } else if (data.isEmpty() || !newData.hasPrevious()) { data.replace(newData); @@ -98,7 +95,7 @@ public class ListAdapter extends Adapter { data.remove(end); notifyItemRemoved(end); } - data.addListAt(newData, end); + data.addAt(newData, end); notifyItemRangeInserted(end, newData.size()); } disableLoading(); @@ -111,7 +108,7 @@ public class ListAdapter extends Adapter { * @param list updated list */ @MainThread - public void updateItem(UserList list) { + public void updateItem(TwitterList list) { int index = data.indexOf(list); if (index >= 0) { data.set(index, list); @@ -120,18 +117,15 @@ public class ListAdapter extends Adapter { } /** - * remove userlist item from list + * remove user list item from list * - * @param itemId userlist id to remove + * @param itemId user list id to remove */ @MainThread public void removeItem(long itemId) { - for (int index = 0; index < data.size(); index++) { - if (data.get(index).getId() == itemId) { - data.remove(index); - notifyItemRemoved(index); - break; - } + int index = data.removeItem(itemId); + if (index >= 0) { + notifyItemRemoved(index); } } @@ -155,44 +149,46 @@ public class ListAdapter extends Adapter { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == ITEM_LIST) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false); - final ListHolder vh = new ListHolder(v, settings); - vh.profile_img.setOnClickListener(new OnClickListener() { + final ListHolder itemHolder = new ListHolder(v, settings); + itemHolder.profile_img.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - int position = vh.getLayoutPosition(); + int position = itemHolder.getLayoutPosition(); if (position != NO_POSITION) { - User user = data.get(position).getListOwner(); - listener.onProfileClick(user); + TwitterList item = data.get(position); + if (item != null) { + listener.onProfileClick(item.getListOwner()); + } } } }); v.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - int position = vh.getLayoutPosition(); + int position = itemHolder.getLayoutPosition(); if (position != NO_POSITION) { - UserList list = data.get(position); + TwitterList list = data.get(position); listener.onListClick(list); } } }); - return vh; + return itemHolder; } else { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_placeholder, parent, false); - final PlaceHolder ph = new PlaceHolder(v, settings); - ph.loadBtn.setOnClickListener(new OnClickListener() { + final Footer footer = new Footer(v, settings); + footer.loadBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - int position = ph.getLayoutPosition(); + int position = footer.getLayoutPosition(); if (position != NO_POSITION) { listener.onFooterClick(data.getNext()); - ph.loadCircle.setVisibility(VISIBLE); - ph.loadBtn.setVisibility(INVISIBLE); + footer.loadCircle.setVisibility(VISIBLE); + footer.loadBtn.setVisibility(INVISIBLE); loadingIndex = position; } } }); - return ph; + return footer; } } @@ -201,54 +197,56 @@ public class ListAdapter extends Adapter { public void onBindViewHolder(@NonNull ViewHolder holder, int index) { if (holder instanceof ListHolder) { ListHolder vh = (ListHolder) holder; - UserList item = data.get(index); - User owner = item.getListOwner(); - vh.textViews[0].setText(item.getTitle()); - vh.textViews[1].setText(item.getDescription()); - vh.textViews[2].setText(owner.getUsername()); - vh.textViews[3].setText(owner.getScreenname()); - vh.textViews[4].setText(getTimeString(item.getCreatedAt())); - vh.textViews[5].setText(formatter.format(item.getMemberCount())); - vh.textViews[6].setText(formatter.format(item.getSubscriberCount())); - if (settings.getImageLoad() && owner.hasProfileImage()) { - String pbLink = owner.getImageLink(); - if (!owner.hasDefaultProfileImage()) - pbLink += settings.getImageSuffix(); - Picasso.get().load(pbLink).transform(new RoundedCornersTransformation(3, 0)) - .error(R.drawable.no_image).into(vh.profile_img); - } else { - vh.profile_img.setImageResource(0); + TwitterList item = data.get(index); + if (item != null) { + User owner = item.getListOwner(); + vh.textViews[0].setText(item.getTitle()); + vh.textViews[1].setText(item.getDescription()); + vh.textViews[2].setText(owner.getUsername()); + vh.textViews[3].setText(owner.getScreenname()); + vh.textViews[4].setText(getTimeString(item.getCreatedAt())); + vh.textViews[5].setText(formatter.format(item.getMemberCount())); + vh.textViews[6].setText(formatter.format(item.getSubscriberCount())); + if (settings.getImageLoad() && owner.hasProfileImage()) { + String pbLink = owner.getImageLink(); + if (!owner.hasDefaultProfileImage()) + pbLink += settings.getImageSuffix(); + Picasso.get().load(pbLink).transform(new RoundedCornersTransformation(3, 0)) + .error(R.drawable.no_image).into(vh.profile_img); + } else { + vh.profile_img.setImageResource(0); + } + if (!item.isListOwner() && item.isFollowing()) { + vh.icons[6].setVisibility(VISIBLE); + vh.textViews[7].setVisibility(VISIBLE); + } else { + vh.icons[6].setVisibility(GONE); + vh.textViews[7].setVisibility(GONE); + } + if (owner.isVerified()) { + vh.icons[0].setVisibility(VISIBLE); + } else { + vh.icons[0].setVisibility(GONE); + } + if (owner.isLocked()) { + vh.icons[1].setVisibility(VISIBLE); + } else { + vh.icons[1].setVisibility(GONE); + } + if (item.isPrivate()) { + vh.icons[5].setVisibility(VISIBLE); + } else { + vh.icons[5].setVisibility(GONE); + } } - if (!item.isListOwner() && item.isFollowing()) { - vh.icons[6].setVisibility(VISIBLE); - vh.textViews[7].setVisibility(VISIBLE); - } else { - vh.icons[6].setVisibility(GONE); - vh.textViews[7].setVisibility(GONE); - } - if (owner.isVerified()) { - vh.icons[0].setVisibility(VISIBLE); - } else { - vh.icons[0].setVisibility(GONE); - } - if (owner.isLocked()) { - vh.icons[1].setVisibility(VISIBLE); - } else { - vh.icons[1].setVisibility(GONE); - } - if (item.isPrivate()) { - vh.icons[5].setVisibility(VISIBLE); - } else { - vh.icons[5].setVisibility(GONE); - } - } else if (holder instanceof PlaceHolder) { - PlaceHolder placeHolder = (PlaceHolder) holder; + } else if (holder instanceof Footer) { + Footer footer = (Footer) holder; if (loadingIndex != NO_LOADING) { - placeHolder.loadCircle.setVisibility(VISIBLE); - placeHolder.loadBtn.setVisibility(INVISIBLE); + footer.loadCircle.setVisibility(VISIBLE); + footer.loadBtn.setVisibility(INVISIBLE); } else { - placeHolder.loadCircle.setVisibility(INVISIBLE); - placeHolder.loadBtn.setVisibility(VISIBLE); + footer.loadCircle.setVisibility(INVISIBLE); + footer.loadBtn.setVisibility(VISIBLE); } } } @@ -264,75 +262,6 @@ public class ListAdapter extends Adapter { } } - /** - * view holder class for an user list item - */ - private final class ListHolder extends ViewHolder { - - final ImageView[] icons = new ImageView[7]; - final TextView[] textViews = new TextView[8]; - final ImageView profile_img; - - ListHolder(View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - profile_img = v.findViewById(R.id.list_owner_profile); - icons[0] = v.findViewById(R.id.list_user_verified); - icons[1] = v.findViewById(R.id.list_user_locked); - icons[2] = v.findViewById(R.id.list_member_icon); - icons[3] = v.findViewById(R.id.list_subscriber_icon); - icons[4] = v.findViewById(R.id.list_date_icon); - icons[5] = v.findViewById(R.id.list_private); - icons[6] = v.findViewById(R.id.list_follow_icon); - textViews[0] = v.findViewById(R.id.list_title); - textViews[1] = v.findViewById(R.id.list_description); - textViews[2] = v.findViewById(R.id.list_ownername); - textViews[3] = v.findViewById(R.id.list_screenname); - textViews[4] = v.findViewById(R.id.list_createdat); - textViews[5] = v.findViewById(R.id.list_member); - textViews[6] = v.findViewById(R.id.list_subscriber); - textViews[7] = v.findViewById(R.id.list_action); - - icons[0].setImageResource(R.drawable.verify); - icons[1].setImageResource(R.drawable.lock); - icons[2].setImageResource(R.drawable.user); - icons[3].setImageResource(R.drawable.subscriber); - icons[4].setImageResource(R.drawable.calendar); - icons[5].setImageResource(R.drawable.lock); - icons[6].setImageResource(R.drawable.followback); - - for (TextView tv : textViews) { - tv.setTextColor(settings.getFontColor()); - tv.setTypeface(settings.getFontFace()); - } - for (ImageView icon : icons) { - icon.setColorFilter(settings.getIconColor(), SRC_IN); - } - background.setCardBackgroundColor(settings.getCardColor()); - } - } - - /** - * view holder class for a footer view - */ - private final class PlaceHolder extends ViewHolder { - - final ProgressBar loadCircle; - final Button loadBtn; - - PlaceHolder(@NonNull View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - loadCircle = v.findViewById(R.id.placeholder_loading); - loadBtn = v.findViewById(R.id.placeholder_button); - - loadBtn.setTypeface(settings.getFontFace()); - loadBtn.setTextColor(settings.getFontColor()); - AppStyles.setProgressColor(loadCircle, settings.getHighlightColor()); - background.setCardBackgroundColor(settings.getCardColor()); - } - } - /** * Listener for an item */ @@ -343,7 +272,7 @@ public class ListAdapter extends Adapter { * * @param listItem Item data and information */ - void onListClick(UserList listItem); + void onListClick(TwitterList listItem); /** * called when the profile image of the owner was clicked diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/MessageAdapter.java b/app/src/main/java/org/nuclearfog/twidda/adapter/MessageAdapter.java index abbab228..e7403931 100644 --- a/app/src/main/java/org/nuclearfog/twidda/adapter/MessageAdapter.java +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/MessageAdapter.java @@ -1,17 +1,12 @@ package org.nuclearfog.twidda.adapter; import android.text.Spanned; -import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; import androidx.annotation.MainThread; import androidx.annotation.NonNull; -import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.ViewHolder; @@ -20,17 +15,17 @@ import com.squareup.picasso.Picasso; import org.nuclearfog.tag.Tagger; import org.nuclearfog.tag.Tagger.OnTagClickListener; import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.adapter.holder.Footer; +import org.nuclearfog.twidda.adapter.holder.MessageHolder; import org.nuclearfog.twidda.backend.items.Message; import org.nuclearfog.twidda.backend.items.User; +import org.nuclearfog.twidda.backend.lists.MessageList; import org.nuclearfog.twidda.database.GlobalSettings; -import java.util.ArrayList; -import java.util.List; - import jp.wasabeef.picasso.transformations.RoundedCornersTransformation; -import static android.graphics.PorterDuff.Mode.SRC_IN; import static android.view.View.GONE; +import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; import static org.nuclearfog.twidda.backend.utils.StringTools.getTimeString; @@ -43,27 +38,56 @@ import static org.nuclearfog.twidda.backend.utils.StringTools.getTimeString; */ public class MessageAdapter extends Adapter { + private static final int NO_INDEX = -1; + private static final int TYPE_MESSAGE = 0; + private static final int TYPE_FOOTER = 1; + private OnItemSelected itemClickListener; private GlobalSettings settings; - private List messages = new ArrayList<>(); - + private MessageList data = new MessageList(null, null); + private int loadingIndex = NO_INDEX; + /** + * @param settings App settings for theme + * @param itemClickListener click listener + */ public MessageAdapter(GlobalSettings settings, OnItemSelected itemClickListener) { this.itemClickListener = itemClickListener; this.settings = settings; } /** - * replace all messages from list + * set messages * - * @param messageList new message list + * @param newData new message list */ @MainThread - public void replaceAll(@NonNull List messageList) { - messages.clear(); - messages.addAll(messageList); - notifyDataSetChanged(); + public void setData(MessageList newData) { + if (newData.isEmpty()) { + if (!data.isEmpty() && data.peekLast() == null) { + int end = data.size() - 1; + data.remove(end); + notifyItemRemoved(end); + } + } else if (data.isEmpty() || !newData.hasPrev()) { + data.replaceAll(newData); + if (newData.hasNext()) { + // add footer + data.add(null); + } + notifyDataSetChanged(); + } else { + int end = data.size() - 1; + if (!newData.hasNext()) { + // remove footer + data.remove(end); + notifyItemRemoved(end); + } + data.addAt(newData, end); + notifyItemRangeInserted(end, newData.size()); + } + disableLoading(); } /** @@ -73,14 +97,8 @@ public class MessageAdapter extends Adapter { */ @MainThread public void remove(long id) { - int pos = -1; - for (int index = 0; index < messages.size() && pos < 0; index++) { - if (messages.get(index).getId() == id) { - messages.remove(index); - pos = index; - } - } - if (pos != -1) { + int pos = data.removeItem(id); + if (pos >= 0) { notifyItemRemoved(pos); } } @@ -88,126 +106,137 @@ public class MessageAdapter extends Adapter { @Override public long getItemId(int index) { - return messages.get(index).getId(); + Message message = data.get(index); + if (message != null) + return message.getId(); + return -1; } @Override public int getItemCount() { - return messages.size(); + return data.size(); + } + + + @Override + public int getItemViewType(int index) { + if (data.get(index) == null) + return TYPE_FOOTER; + return TYPE_MESSAGE; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_dm, parent, false); - final MessageHolder vh = new MessageHolder(view, settings); - vh.buttons[0].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int position = vh.getLayoutPosition(); - if (position != NO_POSITION) { - itemClickListener.onClick(messages.get(position), OnItemSelected.Action.ANSWER); + if (viewType == TYPE_MESSAGE) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_dm, parent, false); + final MessageHolder vh = new MessageHolder(view, settings); + vh.buttons[0].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int position = vh.getLayoutPosition(); + if (position != NO_POSITION) { + itemClickListener.onClick(data.get(position), OnItemSelected.Action.ANSWER); + } } - } - }); - vh.buttons[1].setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int position = vh.getLayoutPosition(); - if (position != NO_POSITION) { - itemClickListener.onClick(messages.get(position), OnItemSelected.Action.DELETE); + }); + vh.buttons[1].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int position = vh.getLayoutPosition(); + if (position != NO_POSITION) { + itemClickListener.onClick(data.get(position), OnItemSelected.Action.DELETE); + } } - } - }); - vh.profile_img.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int position = vh.getLayoutPosition(); - if (position != NO_POSITION) { - itemClickListener.onClick(messages.get(position), OnItemSelected.Action.PROFILE); + }); + vh.profile_img.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int position = vh.getLayoutPosition(); + if (position != NO_POSITION) { + itemClickListener.onClick(data.get(position), OnItemSelected.Action.PROFILE); + } } - } - }); - return vh; + }); + return vh; + } else { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_placeholder, parent, false); + final Footer footer = new Footer(v, settings); + footer.loadBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int position = footer.getLayoutPosition(); + if (position != NO_POSITION) { + boolean success = itemClickListener.onFooterClick(data.getNextCursor()); + if (success) { + footer.loadCircle.setVisibility(VISIBLE); + footer.loadBtn.setVisibility(INVISIBLE); + loadingIndex = position; + } + } + } + }); + return footer; + } } @Override public void onBindViewHolder(@NonNull ViewHolder vh, int index) { - Spanned text; - Message message = messages.get(index); - User sender = message.getSender(); - text = Tagger.makeTextWithLinks(message.getText(), settings.getHighlightColor(), itemClickListener); + if (vh instanceof MessageHolder) { + Message message = data.get(index); + if (message != null) { + User sender = message.getSender(); + Spanned text = Tagger.makeTextWithLinks(message.getText(), settings.getHighlightColor(), itemClickListener); - MessageHolder holder = (MessageHolder) vh; - holder.textViews[0].setText(sender.getUsername()); - holder.textViews[1].setText(sender.getScreenname()); - holder.textViews[2].setText(message.getReceiver().getScreenname()); - holder.textViews[3].setText(getTimeString(message.getTime())); - holder.textViews[4].setText(text); - if (sender.isVerified()) { - holder.verifiedIcon.setVisibility(VISIBLE); - } else { - holder.verifiedIcon.setVisibility(GONE); - } - if (sender.isLocked()) { - holder.lockedIcon.setVisibility(VISIBLE); - } else { - holder.lockedIcon.setVisibility(GONE); - } - if (settings.getImageLoad() && sender.hasProfileImage()) { - String pbLink = sender.getImageLink(); - if (!sender.hasDefaultProfileImage()) - pbLink += settings.getImageSuffix(); - Picasso.get().load(pbLink).transform(new RoundedCornersTransformation(2, 0)) - .error(R.drawable.no_image).into(holder.profile_img); - } else { - holder.profile_img.setImageResource(0); + MessageHolder holder = (MessageHolder) vh; + holder.textViews[0].setText(sender.getUsername()); + holder.textViews[1].setText(sender.getScreenname()); + holder.textViews[2].setText(message.getReceiver().getScreenname()); + holder.textViews[3].setText(getTimeString(message.getTime())); + holder.textViews[4].setText(text); + if (sender.isVerified()) { + holder.verifiedIcon.setVisibility(VISIBLE); + } else { + holder.verifiedIcon.setVisibility(GONE); + } + if (sender.isLocked()) { + holder.lockedIcon.setVisibility(VISIBLE); + } else { + holder.lockedIcon.setVisibility(GONE); + } + if (settings.getImageLoad() && sender.hasProfileImage()) { + String pbLink = sender.getImageLink(); + if (!sender.hasDefaultProfileImage()) + pbLink += settings.getImageSuffix(); + Picasso.get().load(pbLink).transform(new RoundedCornersTransformation(2, 0)) + .error(R.drawable.no_image).into(holder.profile_img); + } else { + holder.profile_img.setImageResource(0); + } + } + } else if (vh instanceof Footer) { + Footer footer = (Footer) vh; + if (loadingIndex != NO_INDEX) { + footer.loadCircle.setVisibility(VISIBLE); + footer.loadBtn.setVisibility(INVISIBLE); + } else { + footer.loadCircle.setVisibility(INVISIBLE); + footer.loadBtn.setVisibility(VISIBLE); + } } } /** - * Holder class for a message view + * disable loading animation in footer */ - private final class MessageHolder extends ViewHolder { - - final TextView[] textViews = new TextView[5]; - final Button[] buttons = new Button[2]; - final ImageView profile_img, verifiedIcon, lockedIcon; - - MessageHolder(View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - ImageView receiver_icon = v.findViewById(R.id.dm_receiver_icon); - profile_img = v.findViewById(R.id.dm_profile_img); - verifiedIcon = v.findViewById(R.id.dm_user_verified); - lockedIcon = v.findViewById(R.id.dm_user_locked); - textViews[0] = v.findViewById(R.id.dm_username); - textViews[1] = v.findViewById(R.id.dm_screenname); - textViews[2] = v.findViewById(R.id.dm_receiver); - textViews[3] = v.findViewById(R.id.dm_time); - textViews[4] = v.findViewById(R.id.dm_message); - buttons[0] = v.findViewById(R.id.dm_answer); - buttons[1] = v.findViewById(R.id.dm_delete); - - for (TextView tv : textViews) { - tv.setTextColor(settings.getFontColor()); - tv.setTypeface(settings.getFontFace()); - } - for (Button button : buttons) { - button.setTextColor(settings.getFontColor()); - button.setTypeface(settings.getFontFace()); - } - receiver_icon.setImageResource(R.drawable.right); - verifiedIcon.setImageResource(R.drawable.verify); - lockedIcon.setImageResource(R.drawable.lock); - verifiedIcon.setColorFilter(settings.getIconColor(), SRC_IN); - lockedIcon.setColorFilter(settings.getIconColor(), SRC_IN); - receiver_icon.setColorFilter(settings.getIconColor(), SRC_IN); - background.setCardBackgroundColor(settings.getCardColor()); - textViews[4].setMovementMethod(LinkMovementMethod.getInstance()); + public void disableLoading() { + if (loadingIndex != NO_INDEX) { + int oldIndex = loadingIndex; + loadingIndex = NO_INDEX; + notifyItemChanged(oldIndex); } } @@ -219,7 +248,7 @@ public class MessageAdapter extends Adapter { enum Action { ANSWER, DELETE, - PROFILE + PROFILE, } /** @@ -229,5 +258,13 @@ public class MessageAdapter extends Adapter { * @param action what button was clicked */ void onClick(Message message, Action action); + + /** + * called when the footer was clicked + * + * @param cursor message cursor + * @return true if task was started + */ + boolean onFooterClick(String cursor); } } \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/TrendAdapter.java b/app/src/main/java/org/nuclearfog/twidda/adapter/TrendAdapter.java index decbd24b..67702da3 100644 --- a/app/src/main/java/org/nuclearfog/twidda/adapter/TrendAdapter.java +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/TrendAdapter.java @@ -5,15 +5,14 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.TextView; import androidx.annotation.MainThread; import androidx.annotation.NonNull; -import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.adapter.holder.TrendHolder; import org.nuclearfog.twidda.backend.items.Trend; import org.nuclearfog.twidda.database.GlobalSettings; @@ -86,7 +85,7 @@ public class TrendAdapter extends Adapter { @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_trend, parent, false); - final ItemHolder vh = new ItemHolder(v, settings); + final TrendHolder vh = new TrendHolder(v, settings); v.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -102,7 +101,7 @@ public class TrendAdapter extends Adapter { @Override public void onBindViewHolder(@NonNull ViewHolder vh, int index) { - ItemHolder holder = (ItemHolder) vh; + TrendHolder holder = (TrendHolder) vh; Trend trend = trends.get(index); holder.textViews[0].setText(trend.getRankStr()); holder.textViews[1].setText(trend.getName()); @@ -116,28 +115,6 @@ public class TrendAdapter extends Adapter { } } - /** - * view holder class for an item view - */ - private final class ItemHolder extends ViewHolder { - final TextView[] textViews = new TextView[3]; - - ItemHolder(View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - textViews[0] = v.findViewById(R.id.trendpos); - textViews[1] = v.findViewById(R.id.trendname); - textViews[2] = v.findViewById(R.id.trendvol); - - background.setCardBackgroundColor(settings.getCardColor()); - for (TextView tv : textViews) { - tv.setTextColor(settings.getFontColor()); - tv.setTypeface(settings.getFontFace()); - } - } - } - - /** * Listener for trend list */ diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/TweetAdapter.java b/app/src/main/java/org/nuclearfog/twidda/adapter/TweetAdapter.java index 663d9bb5..e3ef4c1f 100644 --- a/app/src/main/java/org/nuclearfog/twidda/adapter/TweetAdapter.java +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/TweetAdapter.java @@ -6,14 +6,9 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.MainThread; import androidx.annotation.NonNull; -import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.ViewHolder; @@ -21,9 +16,10 @@ import com.squareup.picasso.Picasso; import org.nuclearfog.tag.Tagger; import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.adapter.holder.Footer; +import org.nuclearfog.twidda.adapter.holder.TweetHolder; import org.nuclearfog.twidda.backend.items.Tweet; import org.nuclearfog.twidda.backend.items.User; -import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.database.GlobalSettings; import java.text.NumberFormat; @@ -227,11 +223,11 @@ public class TweetAdapter extends Adapter { return vh; } else { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_placeholder, parent, false); - final PlaceHolder vh = new PlaceHolder(v, settings); - vh.loadBtn.setOnClickListener(new OnClickListener() { + final Footer footer = new Footer(v, settings); + footer.loadBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - int position = vh.getLayoutPosition(); + int position = footer.getLayoutPosition(); if (position != NO_POSITION) { long sinceId = 0; long maxId = 0; @@ -243,14 +239,16 @@ public class TweetAdapter extends Adapter { sinceId = tweets.get(position + 1).getId(); maxId = tweets.get(position - 1).getId(); } - itemClickListener.onHolderClick(sinceId, maxId, position); - vh.loadCircle.setVisibility(VISIBLE); - vh.loadBtn.setVisibility(INVISIBLE); - loadingIndex = position; + boolean success = itemClickListener.onHolderClick(sinceId, maxId, position); + if (success) { + footer.loadCircle.setVisibility(VISIBLE); + footer.loadBtn.setVisibility(INVISIBLE); + loadingIndex = position; + } } } }); - return vh; + return footer; } } @@ -259,125 +257,67 @@ public class TweetAdapter extends Adapter { public void onBindViewHolder(@NonNull ViewHolder holder, int index) { Tweet tweet = tweets.get(index); if (holder instanceof TweetHolder && tweet != null) { - TweetHolder vh = (TweetHolder) holder; + TweetHolder tweetItem = (TweetHolder) holder; User user = tweet.getUser(); if (tweet.getEmbeddedTweet() != null) { - vh.textViews[5].setText(user.getScreenname()); - vh.textViews[5].setVisibility(VISIBLE); - vh.rtUser.setVisibility(VISIBLE); + tweetItem.textViews[5].setText(user.getScreenname()); + tweetItem.textViews[5].setVisibility(VISIBLE); + tweetItem.rtUser.setVisibility(VISIBLE); tweet = tweet.getEmbeddedTweet(); user = tweet.getUser(); } else { - vh.textViews[5].setVisibility(INVISIBLE); - vh.rtUser.setVisibility(INVISIBLE); + tweetItem.textViews[5].setVisibility(INVISIBLE); + tweetItem.rtUser.setVisibility(INVISIBLE); } Spanned text = Tagger.makeTextWithLinks(tweet.getTweet(), settings.getHighlightColor()); - vh.textViews[2].setText(text); - vh.textViews[0].setText(user.getUsername()); - vh.textViews[1].setText(user.getScreenname()); - vh.textViews[3].setText(formatter.format(tweet.getRetweetCount())); - vh.textViews[4].setText(formatter.format(tweet.getFavoriteCount())); - vh.textViews[6].setText(getTimeString(tweet.getTime())); + tweetItem.textViews[2].setText(text); + tweetItem.textViews[0].setText(user.getUsername()); + tweetItem.textViews[1].setText(user.getScreenname()); + tweetItem.textViews[3].setText(formatter.format(tweet.getRetweetCount())); + tweetItem.textViews[4].setText(formatter.format(tweet.getFavoriteCount())); + tweetItem.textViews[6].setText(getTimeString(tweet.getTime())); if (tweet.retweeted()) { - vh.rtIcon.setColorFilter(Color.GREEN, SRC_IN); + tweetItem.rtIcon.setColorFilter(Color.GREEN, SRC_IN); } else { - vh.rtIcon.setColorFilter(settings.getIconColor(), SRC_IN); + tweetItem.rtIcon.setColorFilter(settings.getIconColor(), SRC_IN); } if (tweet.favored()) { - vh.favIcon.setColorFilter(Color.YELLOW, SRC_IN); + tweetItem.favIcon.setColorFilter(Color.YELLOW, SRC_IN); } else { - vh.favIcon.setColorFilter(settings.getIconColor(), SRC_IN); + tweetItem.favIcon.setColorFilter(settings.getIconColor(), SRC_IN); } if (user.isVerified()) { - vh.verifiedIcon.setVisibility(VISIBLE); + tweetItem.verifiedIcon.setVisibility(VISIBLE); } else { - vh.verifiedIcon.setVisibility(GONE); + tweetItem.verifiedIcon.setVisibility(GONE); } if (user.isLocked()) { - vh.lockedIcon.setVisibility(VISIBLE); + tweetItem.lockedIcon.setVisibility(VISIBLE); } else { - vh.lockedIcon.setVisibility(GONE); + tweetItem.lockedIcon.setVisibility(GONE); } if (settings.getImageLoad() && user.hasProfileImage()) { String pbLink = user.getImageLink(); if (!user.hasDefaultProfileImage()) pbLink += settings.getImageSuffix(); Picasso.get().load(pbLink).transform(new RoundedCornersTransformation(2, 0)) - .error(R.drawable.no_image).into(vh.profile); + .error(R.drawable.no_image).into(tweetItem.profile); } else { - vh.profile.setImageResource(0); + tweetItem.profile.setImageResource(0); } - } else if (holder instanceof PlaceHolder) { - PlaceHolder vh = (PlaceHolder) holder; + } else if (holder instanceof Footer) { + Footer footer = (Footer) holder; if (loadingIndex != NO_INDEX) { - vh.loadCircle.setVisibility(VISIBLE); - vh.loadBtn.setVisibility(INVISIBLE); + footer.loadCircle.setVisibility(VISIBLE); + footer.loadBtn.setVisibility(INVISIBLE); } else { - vh.loadCircle.setVisibility(INVISIBLE); - vh.loadBtn.setVisibility(VISIBLE); + footer.loadCircle.setVisibility(INVISIBLE); + footer.loadBtn.setVisibility(VISIBLE); } } } - /** - * Holder class for the tweet view - */ - private final class TweetHolder extends ViewHolder { - final TextView[] textViews = new TextView[7]; - final ImageView profile, rtUser, verifiedIcon, lockedIcon, rtIcon, favIcon; - - TweetHolder(@NonNull View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - profile = v.findViewById(R.id.tweetPb); - verifiedIcon = v.findViewById(R.id.verified_icon); - lockedIcon = v.findViewById(R.id.locked_icon); - rtUser = v.findViewById(R.id.rt_user_icon); - rtIcon = v.findViewById(R.id.rt_icon); - favIcon = v.findViewById(R.id.fav_icon); - textViews[0] = v.findViewById(R.id.username); - textViews[1] = v.findViewById(R.id.screenname); - textViews[2] = v.findViewById(R.id.tweettext); - textViews[3] = v.findViewById(R.id.retweet_number); - textViews[4] = v.findViewById(R.id.favorite_number); - textViews[5] = v.findViewById(R.id.retweeter); - textViews[6] = v.findViewById(R.id.time); - - for (TextView tv : textViews) { - tv.setTextColor(settings.getFontColor()); - tv.setTypeface(settings.getFontFace()); - } - verifiedIcon.setImageResource(R.drawable.verify); - lockedIcon.setImageResource(R.drawable.lock); - rtUser.setImageResource(R.drawable.retweet); - rtIcon.setImageResource(R.drawable.retweet); - favIcon.setImageResource(R.drawable.favorite); - verifiedIcon.setColorFilter(settings.getIconColor(), SRC_IN); - lockedIcon.setColorFilter(settings.getIconColor(), SRC_IN); - rtUser.setColorFilter(settings.getIconColor(), SRC_IN); - background.setCardBackgroundColor(settings.getCardColor()); - } - } - - /** - * Holder class for the placeholder view - */ - private final class PlaceHolder extends ViewHolder { - final Button loadBtn; - final ProgressBar loadCircle; - - PlaceHolder(@NonNull View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - loadBtn = v.findViewById(R.id.placeholder_button); - loadCircle = v.findViewById(R.id.placeholder_loading); - - background.setCardBackgroundColor(settings.getCardColor()); - AppStyles.setProgressColor(loadCircle, settings.getHighlightColor()); - } - } - /** * Listener for tweet click */ @@ -396,7 +336,8 @@ public class TweetAdapter extends Adapter { * @param sinceId the tweet ID of the tweet below the holder * @param maxId the tweet ID of the tweet over the holder * @param pos position of the holder + * @return true if click was handled */ - void onHolderClick(long sinceId, long maxId, int pos); + boolean onHolderClick(long sinceId, long maxId, int pos); } } \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/UserAdapter.java b/app/src/main/java/org/nuclearfog/twidda/adapter/UserAdapter.java index c5160e94..75a22e38 100644 --- a/app/src/main/java/org/nuclearfog/twidda/adapter/UserAdapter.java +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/UserAdapter.java @@ -4,31 +4,25 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.MainThread; import androidx.annotation.NonNull; -import androidx.cardview.widget.CardView; import androidx.recyclerview.widget.RecyclerView.Adapter; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.squareup.picasso.Picasso; import org.nuclearfog.twidda.R; -import org.nuclearfog.twidda.backend.holder.TwitterUserList; +import org.nuclearfog.twidda.adapter.holder.Footer; +import org.nuclearfog.twidda.adapter.holder.UserHolder; import org.nuclearfog.twidda.backend.items.User; -import org.nuclearfog.twidda.backend.utils.AppStyles; +import org.nuclearfog.twidda.backend.lists.UserList; import org.nuclearfog.twidda.database.GlobalSettings; import java.text.NumberFormat; import jp.wasabeef.picasso.transformations.RoundedCornersTransformation; -import static android.graphics.PorterDuff.Mode.SRC_IN; import static android.view.View.GONE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; @@ -58,11 +52,12 @@ public class UserAdapter extends Adapter { */ private static final int ITEM_GAP = 1; + private static final NumberFormat FORMATTER = NumberFormat.getIntegerInstance(); + private UserClickListener itemClickListener; private GlobalSettings settings; - private TwitterUserList items = new TwitterUserList(); - private NumberFormat formatter = NumberFormat.getIntegerInstance(); + private UserList data = new UserList(); private int loadingIndex = NO_INDEX; private boolean userRemovable = false; @@ -81,27 +76,29 @@ public class UserAdapter extends Adapter { * @param newData new userlist */ @MainThread - public void setData(@NonNull TwitterUserList newData) { + public void setData(@NonNull UserList newData) { if (newData.isEmpty()) { - if (!items.isEmpty() && items.peekLast() == null) { + if (!data.isEmpty() && data.peekLast() == null) { // remove footer - items.pollLast(); + int end = data.size() - 1; + data.remove(end); + notifyItemRemoved(end); } - } else if (items.isEmpty() || !newData.hasPrevious()) { - items.replace(newData); + } else if (data.isEmpty() || !newData.hasPrevious()) { + data.replace(newData); if (newData.hasNext()) { // add footer - items.add(null); + data.add(null); } notifyDataSetChanged(); } else { - int end = items.size() - 1; + int end = data.size() - 1; if (!newData.hasNext()) { // remove footer - items.remove(end); + data.remove(end); notifyItemRemoved(end); } - items.addListAt(newData, end); + data.addAt(newData, end); notifyItemRangeInserted(end, newData.size()); } disableLoading(); @@ -114,9 +111,9 @@ public class UserAdapter extends Adapter { */ @MainThread public void updateUser(User user) { - int index = items.indexOf(user); + int index = data.indexOf(user); if (index >= 0) { - items.set(index, user); + data.set(index, user); notifyItemChanged(index); } } @@ -124,37 +121,36 @@ public class UserAdapter extends Adapter { /** * remove user from adapter * - * @param username User to remove + * @param screenname User to remove */ @MainThread - public void removeUser(String username) { - for (int pos = 0; pos < items.size(); pos++) { - if (items.get(pos).getScreenname().equals(username)) { - items.remove(pos); - notifyItemRemoved(pos); - break; - } + public void removeUser(String screenname) { + int pos = data.removeItem(screenname); + if (pos >= 0) { + data.remove(pos); + notifyItemRemoved(pos); } } @Override public int getItemCount() { - return items.size(); + return data.size(); } @Override public long getItemId(int index) { - if (items.get(index) != null) - return items.get(index).getId(); + User user = data.get(index); + if (user != null) + return user.getId(); return NO_ID; } @Override public int getItemViewType(int index) { - if (items.get(index) == null) + if (data.get(index) == null) return ITEM_GAP; return ITEM_USER; } @@ -165,12 +161,12 @@ public class UserAdapter extends Adapter { public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { if (viewType == ITEM_USER) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_user, parent, false); - final ItemHolder vh = new ItemHolder(v, settings); + final UserHolder vh = new UserHolder(v, settings); v.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int position = vh.getLayoutPosition(); - User user = items.get(position); + User user = data.get(position); if (position != NO_POSITION && user != null) { itemClickListener.onUserClick(user); } @@ -182,7 +178,7 @@ public class UserAdapter extends Adapter { @Override public void onClick(View v) { int position = vh.getLayoutPosition(); - User user = items.get(position); + User user = data.get(position); if (position != NO_POSITION && user != null) { itemClickListener.onDelete(user.getScreenname()); } @@ -194,16 +190,18 @@ public class UserAdapter extends Adapter { return vh; } else { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_placeholder, parent, false); - final PlaceHolder vh = new PlaceHolder(v, settings); + final Footer vh = new Footer(v, settings); vh.loadBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int position = vh.getLayoutPosition(); if (position != NO_POSITION) { - itemClickListener.onFooterClick(items.getNext()); - vh.loadCircle.setVisibility(VISIBLE); - vh.loadBtn.setVisibility(INVISIBLE); - loadingIndex = position; + boolean success = itemClickListener.onFooterClick(data.getNext()); + if (success) { + vh.loadCircle.setVisibility(VISIBLE); + vh.loadBtn.setVisibility(INVISIBLE); + loadingIndex = position; + } } } }); @@ -214,34 +212,34 @@ public class UserAdapter extends Adapter { @Override public void onBindViewHolder(@NonNull ViewHolder holder, int index) { - User user = items.get(index); - if (holder instanceof ItemHolder && user != null) { - ItemHolder vh = (ItemHolder) holder; - vh.username.setText(user.getUsername()); - vh.screenname.setText(user.getScreenname()); - vh.following.setText(formatter.format(user.getFollowing())); - vh.follower.setText(formatter.format(user.getFollower())); + User user = data.get(index); + if (holder instanceof UserHolder && user != null) { + UserHolder userholder = (UserHolder) holder; + userholder.textViews[0].setText(user.getUsername()); + userholder.textViews[1].setText(user.getScreenname()); + userholder.textViews[2].setText(FORMATTER.format(user.getFollowing())); + userholder.textViews[3].setText(FORMATTER.format(user.getFollower())); if (user.isVerified()) { - vh.verifyIcon.setVisibility(VISIBLE); + userholder.verifyIcon.setVisibility(VISIBLE); } else { - vh.verifyIcon.setVisibility(GONE); + userholder.verifyIcon.setVisibility(GONE); } if (user.isLocked()) { - vh.lockedIcon.setVisibility(VISIBLE); + userholder.lockedIcon.setVisibility(VISIBLE); } else { - vh.lockedIcon.setVisibility(GONE); + userholder.lockedIcon.setVisibility(GONE); } if (settings.getImageLoad() && user.hasProfileImage()) { String pbLink = user.getImageLink(); if (!user.hasDefaultProfileImage()) pbLink += settings.getImageSuffix(); Picasso.get().load(pbLink).transform(new RoundedCornersTransformation(2, 0)) - .error(R.drawable.no_image).into(vh.profileImg); + .error(R.drawable.no_image).into(userholder.profileImg); } else { - vh.profileImg.setImageResource(0); + userholder.profileImg.setImageResource(0); } - } else if (holder instanceof PlaceHolder) { - PlaceHolder vh = (PlaceHolder) holder; + } else if (holder instanceof Footer) { + Footer vh = (Footer) holder; if (loadingIndex != NO_INDEX) { vh.loadCircle.setVisibility(VISIBLE); vh.loadBtn.setVisibility(INVISIBLE); @@ -272,71 +270,6 @@ public class UserAdapter extends Adapter { userRemovable = enable; } - /** - * Holder for an user view item - */ - private final class ItemHolder extends ViewHolder { - - final TextView username, screenname, following, follower; - final ImageView profileImg, verifyIcon, lockedIcon; - final ImageButton delete; - - ItemHolder(View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - ImageView followingIcon = v.findViewById(R.id.following_icon); - ImageView followerIcon = v.findViewById(R.id.follower_icon); - username = v.findViewById(R.id.username_detail); - screenname = v.findViewById(R.id.screenname_detail); - following = v.findViewById(R.id.item_user_friends); - follower = v.findViewById(R.id.item_user_follower); - profileImg = v.findViewById(R.id.user_profileimg); - verifyIcon = v.findViewById(R.id.useritem_verified); - lockedIcon = v.findViewById(R.id.useritem_locked); - delete = v.findViewById(R.id.useritem_del_user); - - followerIcon.setImageResource(R.drawable.follower); - followingIcon.setImageResource(R.drawable.following); - verifyIcon.setImageResource(R.drawable.verify); - lockedIcon.setImageResource(R.drawable.lock); - delete.setImageResource(R.drawable.cross); - - background.setCardBackgroundColor(settings.getCardColor()); - followerIcon.setColorFilter(settings.getIconColor(), SRC_IN); - followingIcon.setColorFilter(settings.getIconColor(), SRC_IN); - verifyIcon.setColorFilter(settings.getIconColor(), SRC_IN); - lockedIcon.setColorFilter(settings.getIconColor(), SRC_IN); - delete.setColorFilter(settings.getIconColor(), SRC_IN); - username.setTextColor(settings.getFontColor()); - username.setTypeface(settings.getFontFace()); - screenname.setTextColor(settings.getFontColor()); - screenname.setTypeface(settings.getFontFace()); - following.setTextColor(settings.getFontColor()); - following.setTypeface(settings.getFontFace()); - follower.setTextColor(settings.getFontColor()); - follower.setTypeface(settings.getFontFace()); - } - } - - /** - * Holder for a footer view - */ - private final class PlaceHolder extends ViewHolder { - final ProgressBar loadCircle; - final Button loadBtn; - - PlaceHolder(@NonNull View v, GlobalSettings settings) { - super(v); - CardView background = (CardView) v; - loadCircle = v.findViewById(R.id.placeholder_loading); - loadBtn = v.findViewById(R.id.placeholder_button); - - background.setCardBackgroundColor(settings.getCardColor()); - AppStyles.setProgressColor(loadCircle, settings.getHighlightColor()); - } - } - - /** * Listener for list click */ @@ -353,8 +286,9 @@ public class UserAdapter extends Adapter { * handle footer click * * @param cursor next cursor of the list + * @return true if click was handled */ - void onFooterClick(long cursor); + boolean onFooterClick(long cursor); /** * remove user from a list diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/holder/Footer.java b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/Footer.java new file mode 100644 index 00000000..05b9985a --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/Footer.java @@ -0,0 +1,37 @@ +package org.nuclearfog.twidda.adapter.holder; + +import android.view.View; +import android.widget.Button; +import android.widget.ProgressBar; + +import androidx.annotation.NonNull; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.backend.utils.AppStyles; +import org.nuclearfog.twidda.database.GlobalSettings; + +/** + * ViewHolder class for a footer/placeholder view + * + * @author nuclearfog + */ +public class Footer extends RecyclerView.ViewHolder { + + public final ProgressBar loadCircle; + public final Button loadBtn; + + public Footer(@NonNull View v, GlobalSettings settings) { + super(v); + CardView background = (CardView) v; + loadCircle = v.findViewById(R.id.placeholder_loading); + loadBtn = v.findViewById(R.id.placeholder_button); + + background.setCardBackgroundColor(settings.getCardColor()); + loadBtn.setTextColor(settings.getFontColor()); + loadBtn.setTypeface(settings.getFontFace()); + AppStyles.setButtonColor(loadBtn, settings.getFontColor()); + AppStyles.setProgressColor(loadCircle, settings.getHighlightColor()); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/holder/ImageItem.java b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/ImageItem.java new file mode 100644 index 00000000..325d1335 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/ImageItem.java @@ -0,0 +1,32 @@ +package org.nuclearfog.twidda.adapter.holder; + +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; + +import androidx.recyclerview.widget.RecyclerView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.backend.utils.AppStyles; +import org.nuclearfog.twidda.database.GlobalSettings; + +/** + * Holder for image item + * + * @author nuclearfog + * @see org.nuclearfog.twidda.adapter.ImageAdapter + */ +public final class ImageItem extends RecyclerView.ViewHolder { + + public final ImageView preview; + public final ImageButton saveButton; + + public ImageItem(View view, GlobalSettings settings) { + super(view); + preview = view.findViewById(R.id.item_image_preview); + saveButton = view.findViewById(R.id.item_image_save); + saveButton.setImageResource(R.drawable.save); + AppStyles.setButtonColor(saveButton, settings.getFontColor()); + AppStyles.setDrawableColor(saveButton, settings.getIconColor()); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/holder/ListHolder.java b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/ListHolder.java new file mode 100644 index 00000000..9bff0834 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/ListHolder.java @@ -0,0 +1,65 @@ +package org.nuclearfog.twidda.adapter.holder; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.database.GlobalSettings; + +import static android.graphics.PorterDuff.Mode.SRC_IN; + +/** + * view holder class for an user list item + * + * @author nuclearfog + * @see android.widget.ListAdapter + */ +public class ListHolder extends RecyclerView.ViewHolder { + + public final ImageView[] icons = new ImageView[7]; + public final TextView[] textViews = new TextView[8]; + public final ImageView profile_img; + + + public ListHolder(View v, GlobalSettings settings) { + super(v); + CardView background = (CardView) v; + profile_img = v.findViewById(R.id.list_owner_profile); + icons[0] = v.findViewById(R.id.list_user_verified); + icons[1] = v.findViewById(R.id.list_user_locked); + icons[2] = v.findViewById(R.id.list_member_icon); + icons[3] = v.findViewById(R.id.list_subscriber_icon); + icons[4] = v.findViewById(R.id.list_date_icon); + icons[5] = v.findViewById(R.id.list_private); + icons[6] = v.findViewById(R.id.list_follow_icon); + textViews[0] = v.findViewById(R.id.list_title); + textViews[1] = v.findViewById(R.id.list_description); + textViews[2] = v.findViewById(R.id.list_ownername); + textViews[3] = v.findViewById(R.id.list_screenname); + textViews[4] = v.findViewById(R.id.list_createdat); + textViews[5] = v.findViewById(R.id.list_member); + textViews[6] = v.findViewById(R.id.list_subscriber); + textViews[7] = v.findViewById(R.id.list_action); + + icons[0].setImageResource(R.drawable.verify); + icons[1].setImageResource(R.drawable.lock); + icons[2].setImageResource(R.drawable.user); + icons[3].setImageResource(R.drawable.subscriber); + icons[4].setImageResource(R.drawable.calendar); + icons[5].setImageResource(R.drawable.lock); + icons[6].setImageResource(R.drawable.followback); + + for (TextView tv : textViews) { + tv.setTextColor(settings.getFontColor()); + tv.setTypeface(settings.getFontFace()); + } + for (ImageView icon : icons) { + icon.setColorFilter(settings.getIconColor(), SRC_IN); + } + background.setCardBackgroundColor(settings.getCardColor()); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/holder/MessageHolder.java b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/MessageHolder.java new file mode 100644 index 00000000..d767a7ba --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/MessageHolder.java @@ -0,0 +1,63 @@ +package org.nuclearfog.twidda.adapter.holder; + +import android.text.method.LinkMovementMethod; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.backend.utils.AppStyles; +import org.nuclearfog.twidda.database.GlobalSettings; + +import static android.graphics.PorterDuff.Mode.SRC_IN; + +/** + * Holder class for a message view + * + * @author nuclearfog + * @see org.nuclearfog.twidda.adapter.MessageAdapter + */ +public class MessageHolder extends RecyclerView.ViewHolder { + + public final TextView[] textViews = new TextView[5]; + public final Button[] buttons = new Button[2]; + public final ImageView profile_img, verifiedIcon, lockedIcon; + + public MessageHolder(View v, GlobalSettings settings) { + super(v); + CardView background = (CardView) v; + ImageView receiver_icon = v.findViewById(R.id.dm_receiver_icon); + profile_img = v.findViewById(R.id.dm_profile_img); + verifiedIcon = v.findViewById(R.id.dm_user_verified); + lockedIcon = v.findViewById(R.id.dm_user_locked); + textViews[0] = v.findViewById(R.id.dm_username); + textViews[1] = v.findViewById(R.id.dm_screenname); + textViews[2] = v.findViewById(R.id.dm_receiver); + textViews[3] = v.findViewById(R.id.dm_time); + textViews[4] = v.findViewById(R.id.dm_message); + buttons[0] = v.findViewById(R.id.dm_answer); + buttons[1] = v.findViewById(R.id.dm_delete); + + for (TextView tv : textViews) { + tv.setTextColor(settings.getFontColor()); + tv.setTypeface(settings.getFontFace()); + } + for (Button button : buttons) { + button.setTextColor(settings.getFontColor()); + button.setTypeface(settings.getFontFace()); + AppStyles.setButtonColor(button, settings.getFontColor()); + } + receiver_icon.setImageResource(R.drawable.right); + verifiedIcon.setImageResource(R.drawable.verify); + lockedIcon.setImageResource(R.drawable.lock); + verifiedIcon.setColorFilter(settings.getIconColor(), SRC_IN); + lockedIcon.setColorFilter(settings.getIconColor(), SRC_IN); + receiver_icon.setColorFilter(settings.getIconColor(), SRC_IN); + background.setCardBackgroundColor(settings.getCardColor()); + textViews[4].setMovementMethod(LinkMovementMethod.getInstance()); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/holder/TrendHolder.java b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/TrendHolder.java new file mode 100644 index 00000000..8defc6de --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/TrendHolder.java @@ -0,0 +1,35 @@ +package org.nuclearfog.twidda.adapter.holder; + +import android.view.View; +import android.widget.TextView; + +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.database.GlobalSettings; + +/** + * ViewHolder for a trend item + * + * @author nuclearfog + * @see org.nuclearfog.twidda.adapter.TrendAdapter + */ +public class TrendHolder extends RecyclerView.ViewHolder { + + public final TextView[] textViews = new TextView[3]; + + public TrendHolder(View v, GlobalSettings settings) { + super(v); + CardView background = (CardView) v; + textViews[0] = v.findViewById(R.id.trendpos); + textViews[1] = v.findViewById(R.id.trendname); + textViews[2] = v.findViewById(R.id.trendvol); + + background.setCardBackgroundColor(settings.getCardColor()); + for (TextView tv : textViews) { + tv.setTextColor(settings.getFontColor()); + tv.setTypeface(settings.getFontFace()); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/holder/TweetHolder.java b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/TweetHolder.java new file mode 100644 index 00000000..d015a763 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/TweetHolder.java @@ -0,0 +1,58 @@ +package org.nuclearfog.twidda.adapter.holder; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.database.GlobalSettings; + +import static android.graphics.PorterDuff.Mode.SRC_IN; + +/** + * Holder class for the tweet view + * + * @author nuclearfog + * @see org.nuclearfog.twidda.adapter.TweetAdapter + */ +public class TweetHolder extends RecyclerView.ViewHolder { + public final TextView[] textViews = new TextView[7]; + public final ImageView profile, rtUser, verifiedIcon, lockedIcon, rtIcon, favIcon; + + public TweetHolder(@NonNull View v, GlobalSettings settings) { + super(v); + CardView background = (CardView) v; + profile = v.findViewById(R.id.tweetPb); + verifiedIcon = v.findViewById(R.id.verified_icon); + lockedIcon = v.findViewById(R.id.locked_icon); + rtUser = v.findViewById(R.id.rt_user_icon); + rtIcon = v.findViewById(R.id.rt_icon); + favIcon = v.findViewById(R.id.fav_icon); + textViews[0] = v.findViewById(R.id.username); + textViews[1] = v.findViewById(R.id.screenname); + textViews[2] = v.findViewById(R.id.tweettext); + textViews[3] = v.findViewById(R.id.retweet_number); + textViews[4] = v.findViewById(R.id.favorite_number); + textViews[5] = v.findViewById(R.id.retweeter); + textViews[6] = v.findViewById(R.id.time); + + verifiedIcon.setImageResource(R.drawable.verify); + lockedIcon.setImageResource(R.drawable.lock); + rtUser.setImageResource(R.drawable.retweet); + rtIcon.setImageResource(R.drawable.retweet); + favIcon.setImageResource(R.drawable.favorite); + verifiedIcon.setColorFilter(settings.getIconColor(), SRC_IN); + lockedIcon.setColorFilter(settings.getIconColor(), SRC_IN); + rtUser.setColorFilter(settings.getIconColor(), SRC_IN); + background.setCardBackgroundColor(settings.getCardColor()); + + for (TextView tv : textViews) { + tv.setTextColor(settings.getFontColor()); + tv.setTypeface(settings.getFontFace()); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/adapter/holder/UserHolder.java b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/UserHolder.java new file mode 100644 index 00000000..c6851e50 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/adapter/holder/UserHolder.java @@ -0,0 +1,62 @@ +package org.nuclearfog.twidda.adapter.holder; + +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.RecyclerView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.backend.utils.AppStyles; +import org.nuclearfog.twidda.database.GlobalSettings; + +import static android.graphics.PorterDuff.Mode.SRC_IN; + +/** + * View holder class for user item + * + * @author nuclearfog + * @see org.nuclearfog.twidda.adapter.UserAdapter + */ +public class UserHolder extends RecyclerView.ViewHolder { + + public final TextView[] textViews = new TextView[4]; + public final ImageView profileImg, verifyIcon, lockedIcon; + public final ImageButton delete; + + public UserHolder(View v, GlobalSettings settings) { + super(v); + CardView background = (CardView) v; + ImageView followingIcon = v.findViewById(R.id.following_icon); + ImageView followerIcon = v.findViewById(R.id.follower_icon); + textViews[0] = v.findViewById(R.id.username_detail); + textViews[1] = v.findViewById(R.id.screenname_detail); + textViews[2] = v.findViewById(R.id.item_user_friends); + textViews[3] = v.findViewById(R.id.item_user_follower); + profileImg = v.findViewById(R.id.user_profileimg); + verifyIcon = v.findViewById(R.id.useritem_verified); + lockedIcon = v.findViewById(R.id.useritem_locked); + delete = v.findViewById(R.id.useritem_del_user); + + followerIcon.setImageResource(R.drawable.follower); + followingIcon.setImageResource(R.drawable.following); + verifyIcon.setImageResource(R.drawable.verify); + lockedIcon.setImageResource(R.drawable.lock); + delete.setImageResource(R.drawable.cross); + + background.setCardBackgroundColor(settings.getCardColor()); + followerIcon.setColorFilter(settings.getIconColor(), SRC_IN); + followingIcon.setColorFilter(settings.getIconColor(), SRC_IN); + verifyIcon.setColorFilter(settings.getIconColor(), SRC_IN); + lockedIcon.setColorFilter(settings.getIconColor(), SRC_IN); + delete.setColorFilter(settings.getIconColor(), SRC_IN); + + AppStyles.setButtonColor(delete, settings.getFontColor()); + for (TextView tv : textViews) { + tv.setTextColor(settings.getFontColor()); + tv.setTypeface(settings.getFontFace()); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/ListAction.java b/app/src/main/java/org/nuclearfog/twidda/backend/ListAction.java index 15e3d55f..3f1b40f8 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/ListAction.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/ListAction.java @@ -5,7 +5,7 @@ import android.os.AsyncTask; import org.nuclearfog.twidda.activity.ListDetail; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.engine.TwitterEngine; -import org.nuclearfog.twidda.backend.items.UserList; +import org.nuclearfog.twidda.backend.items.TwitterList; import java.lang.ref.WeakReference; @@ -14,7 +14,7 @@ import java.lang.ref.WeakReference; * * @author nuclearfog */ -public class ListAction extends AsyncTask { +public class ListAction extends AsyncTask { /** * Actions to perform @@ -58,7 +58,7 @@ public class ListAction extends AsyncTask { @Override - protected UserList doInBackground(Long... ids) { + protected TwitterList doInBackground(Long... ids) { try { long listId = ids[0]; switch (action) { @@ -83,7 +83,7 @@ public class ListAction extends AsyncTask { @Override - protected void onPostExecute(UserList userList) { + protected void onPostExecute(TwitterList userList) { ListDetail callback = this.callback.get(); if (callback != null) { if (userList != null) { diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/ListLoader.java b/app/src/main/java/org/nuclearfog/twidda/backend/ListLoader.java index 24bdd757..cfa0e098 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/ListLoader.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/ListLoader.java @@ -6,7 +6,7 @@ import androidx.annotation.Nullable; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.engine.TwitterEngine; -import org.nuclearfog.twidda.backend.holder.UserListList; +import org.nuclearfog.twidda.backend.lists.UserLists; import org.nuclearfog.twidda.fragment.UserListFragment; import java.lang.ref.WeakReference; @@ -18,7 +18,7 @@ import java.lang.ref.WeakReference; * @author nuclearfog * @see UserListFragment */ -public class ListLoader extends AsyncTask { +public class ListLoader extends AsyncTask { public static final long NO_CURSOR = -1; @@ -62,7 +62,7 @@ public class ListLoader extends AsyncTask { @Override - protected UserListList doInBackground(Long[] param) { + protected UserLists doInBackground(Long[] param) { try { switch (listType) { case LOAD_USERLISTS: @@ -79,7 +79,7 @@ public class ListLoader extends AsyncTask { @Override - protected void onPostExecute(UserListList result) { + protected void onPostExecute(UserLists result) { if (callback.get() != null) { if (result != null) { callback.get().setData(result); diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/ListUpdater.java b/app/src/main/java/org/nuclearfog/twidda/backend/ListUpdater.java index d29f637a..46f81cbe 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/ListUpdater.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/ListUpdater.java @@ -6,7 +6,7 @@ import org.nuclearfog.twidda.activity.ListEditor; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.engine.TwitterEngine; import org.nuclearfog.twidda.backend.holder.ListHolder; -import org.nuclearfog.twidda.backend.items.UserList; +import org.nuclearfog.twidda.backend.items.TwitterList; import java.lang.ref.WeakReference; @@ -16,7 +16,7 @@ import java.lang.ref.WeakReference; * * @author nuclearfog */ -public class ListUpdater extends AsyncTask { +public class ListUpdater extends AsyncTask { private EngineException err; @@ -32,7 +32,7 @@ public class ListUpdater extends AsyncTask { @Override - protected UserList doInBackground(ListHolder... listHolders) { + protected TwitterList doInBackground(ListHolder... listHolders) { try { ListHolder mList = listHolders[0]; return mTwitter.updateUserList(mList); @@ -44,7 +44,7 @@ public class ListUpdater extends AsyncTask { @Override - protected void onPostExecute(UserList result) { + protected void onPostExecute(TwitterList result) { if (callback.get() != null) { if (result != null) { callback.get().onSuccess(result); diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/MessageLoader.java b/app/src/main/java/org/nuclearfog/twidda/backend/MessageLoader.java index db06f175..39187e96 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/MessageLoader.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/MessageLoader.java @@ -6,12 +6,11 @@ import androidx.annotation.Nullable; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.engine.TwitterEngine; -import org.nuclearfog.twidda.backend.items.Message; +import org.nuclearfog.twidda.backend.lists.MessageList; import org.nuclearfog.twidda.database.AppDatabase; import org.nuclearfog.twidda.fragment.MessageFragment; import java.lang.ref.WeakReference; -import java.util.List; /** @@ -20,7 +19,7 @@ import java.util.List; * @author nuclearfog * @see MessageFragment */ -public class MessageLoader extends AsyncTask> { +public class MessageLoader extends AsyncTask { /** * action to perform @@ -47,38 +46,40 @@ public class MessageLoader extends AsyncTask> { private final AppDatabase db; private final Action action; + private String cursor; private long removeMsgId = -1; /** * @param callback Callback to update data * @param action what action should be performed */ - public MessageLoader(MessageFragment callback, Action action) { + public MessageLoader(MessageFragment callback, Action action, String cursor) { super(); this.callback = new WeakReference<>(callback); db = new AppDatabase(callback.getContext()); mTwitter = TwitterEngine.getInstance(callback.getContext()); this.action = action; + this.cursor = cursor; } @Override - protected List doInBackground(Long[] param) { + protected MessageList doInBackground(Long[] param) { long messageId = 0; try { switch (action) { case DB: - List messages = db.getMessages(); + // TODO store cursor in the preferences + MessageList messages = db.getMessages(); if (messages.isEmpty()) { - messages = mTwitter.getMessages(); + messages = mTwitter.getMessages(null); db.storeMessage(messages); } return messages; case LOAD: - messages = mTwitter.getMessages(); + messages = mTwitter.getMessages(cursor); db.storeMessage(messages); - messages = db.getMessages(); return messages; case DEL: @@ -100,7 +101,7 @@ public class MessageLoader extends AsyncTask> { @Override - protected void onPostExecute(@Nullable List messages) { + protected void onPostExecute(@Nullable MessageList messages) { if (callback.get() != null) { if (messages != null) { callback.get().setData(messages); diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java b/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java index eb914208..05fceb10 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/UserLoader.java @@ -6,7 +6,7 @@ import androidx.annotation.Nullable; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.engine.TwitterEngine; -import org.nuclearfog.twidda.backend.holder.TwitterUserList; +import org.nuclearfog.twidda.backend.lists.UserList; import org.nuclearfog.twidda.fragment.UserFragment; import java.lang.ref.WeakReference; @@ -17,7 +17,7 @@ import java.lang.ref.WeakReference; * @author nuclearfog * @see UserFragment */ -public class UserLoader extends AsyncTask { +public class UserLoader extends AsyncTask { public static final long NO_CURSOR = -1; @@ -77,7 +77,7 @@ public class UserLoader extends AsyncTask { @Override - protected TwitterUserList doInBackground(Long[] param) { + protected UserList doInBackground(Long[] param) { try { long cursor = param[0]; switch (type) { @@ -112,7 +112,7 @@ public class UserLoader extends AsyncTask { @Override - protected void onPostExecute(TwitterUserList users) { + protected void onPostExecute(UserList users) { if (callback.get() != null) { if (users != null) { callback.get().setData(users); diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java b/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java index e9c4f3ee..12fbd07c 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/engine/TwitterEngine.java @@ -10,15 +10,16 @@ import androidx.annotation.Nullable; import org.nuclearfog.twidda.backend.holder.ListHolder; import org.nuclearfog.twidda.backend.holder.MessageHolder; import org.nuclearfog.twidda.backend.holder.TweetHolder; -import org.nuclearfog.twidda.backend.holder.TwitterUserList; -import org.nuclearfog.twidda.backend.holder.UserListList; import org.nuclearfog.twidda.backend.items.Message; import org.nuclearfog.twidda.backend.items.Relation; import org.nuclearfog.twidda.backend.items.Trend; import org.nuclearfog.twidda.backend.items.TrendLocation; import org.nuclearfog.twidda.backend.items.Tweet; +import org.nuclearfog.twidda.backend.items.TwitterList; import org.nuclearfog.twidda.backend.items.User; -import org.nuclearfog.twidda.backend.items.UserList; +import org.nuclearfog.twidda.backend.lists.MessageList; +import org.nuclearfog.twidda.backend.lists.UserList; +import org.nuclearfog.twidda.backend.lists.UserLists; import org.nuclearfog.twidda.database.GlobalSettings; import java.io.File; @@ -36,6 +37,7 @@ import javax.net.ssl.SSLParameters; import io.michaelrocks.paranoid.Obfuscate; import twitter4j.DirectMessage; +import twitter4j.DirectMessageList; import twitter4j.GeoLocation; import twitter4j.IDs; import twitter4j.Location; @@ -320,7 +322,7 @@ public class TwitterEngine { * @return List of Users * @throws EngineException if access is unavailable */ - public TwitterUserList searchUsers(String search, long cursor) throws EngineException { + public UserList searchUsers(String search, long cursor) throws EngineException { try { int currentPage = 1; if (cursor > 0) @@ -330,7 +332,7 @@ public class TwitterEngine { List users = convertUserList(twitter.searchUsers(search, currentPage)); if (users.size() < 20) nextPage = 0; - TwitterUserList result = new TwitterUserList(prevPage, nextPage); + UserList result = new UserList(prevPage, nextPage); result.addAll(users); return result; } catch (Exception err) { @@ -585,14 +587,14 @@ public class TwitterEngine { * @return List of Following User with cursors * @throws EngineException if Access is unavailable */ - public TwitterUserList getFollowing(long userId, long cursor) throws EngineException { + public UserList getFollowing(long userId, long cursor) throws EngineException { try { int load = settings.getListSize(); IDs userIDs = twitter.getFriendsIDs(userId, cursor, load); long[] ids = userIDs.getIDs(); long prevCursor = cursor > 0 ? cursor : 0; long nextCursor = userIDs.getNextCursor(); - TwitterUserList result = new TwitterUserList(prevCursor, nextCursor); + UserList result = new UserList(prevCursor, nextCursor); if (ids.length > 0) { result.addAll(convertUserList(twitter.lookupUsers(ids))); } @@ -610,14 +612,14 @@ public class TwitterEngine { * @return List of Follower with cursors attached * @throws EngineException if Access is unavailable */ - public TwitterUserList getFollower(long userId, long cursor) throws EngineException { + public UserList getFollower(long userId, long cursor) throws EngineException { try { int load = settings.getListSize(); IDs userIDs = twitter.getFollowersIDs(userId, cursor, load); long[] ids = userIDs.getIDs(); long prevCursor = cursor > 0 ? cursor : 0; long nextCursor = userIDs.getNextCursor(); - TwitterUserList result = new TwitterUserList(prevCursor, nextCursor); + UserList result = new UserList(prevCursor, nextCursor); if (ids.length > 0) { result.addAll(convertUserList(twitter.lookupUsers(ids))); } @@ -806,14 +808,14 @@ public class TwitterEngine { * @return List of users or empty list if no match * @throws EngineException if Access is unavailable */ - public TwitterUserList getRetweeter(long tweetID, long cursor) throws EngineException { + public UserList getRetweeter(long tweetID, long cursor) throws EngineException { try { int load = settings.getListSize(); IDs userIDs = twitter.getRetweeterIds(tweetID, load, cursor); long[] ids = userIDs.getIDs(); long prevCursor = cursor > 0 ? cursor : 0; long nextCursor = userIDs.getNextCursor(); // fixme next cursor always zero - TwitterUserList result = new TwitterUserList(prevCursor, nextCursor); + UserList result = new UserList(prevCursor, nextCursor); if (ids.length > 0) { result.addAll(convertUserList(twitter.lookupUsers(ids))); } @@ -827,14 +829,19 @@ public class TwitterEngine { /** * get list of Direct Messages * - * @return DM List + * @param cursor list cursor + * @return list of messages * @throws EngineException if access is unavailable */ - public List getMessages() throws EngineException { + public MessageList getMessages(@Nullable String cursor) throws EngineException { try { + DirectMessageList dmList; int load = settings.getListSize(); - List dmList = twitter.getDirectMessages(load); - List result = new LinkedList<>(); + if (cursor != null) + dmList = twitter.getDirectMessages(load, cursor); + else + dmList = twitter.getDirectMessages(load); + MessageList result = new MessageList(cursor, dmList.getNextCursor()); for (DirectMessage dm : dmList) { try { result.add(getMessage(dm)); @@ -918,7 +925,7 @@ public class TwitterEngine { * @return list information * @throws EngineException if access is unavailable */ - public UserListList getUserList(long userId, String username, long cursor) throws EngineException { + public UserLists getUserList(long userId, String username, long cursor) throws EngineException { try { List lists; if (userId > 0) @@ -927,9 +934,9 @@ public class TwitterEngine { lists = twitter.getUserLists(username); long prevCursor = cursor > 0 ? cursor : 0; long nextCursor = 0; - UserListList result = new UserListList(prevCursor, nextCursor); // todo add paging system + UserLists result = new UserLists(prevCursor, nextCursor); // todo add paging system for (twitter4j.UserList list : lists) - result.add(new UserList(list, twitter.getId())); + result.add(new TwitterList(list, twitter.getId())); return result; } catch (Exception err) { throw new EngineException(err); @@ -945,7 +952,7 @@ public class TwitterEngine { * @return a list of user lists * @throws EngineException if access is unavailable */ - public UserListList getUserListMemberships(long userId, String username, long cursor) throws EngineException { + public UserLists getUserListMemberships(long userId, String username, long cursor) throws EngineException { try { int count = settings.getListSize(); PagableResponseList lists; @@ -955,9 +962,9 @@ public class TwitterEngine { lists = twitter.getUserListMemberships(username, count, cursor); long prevCursor = cursor > 0 ? cursor : 0; long nextCursor = lists.getNextCursor(); - UserListList result = new UserListList(prevCursor, nextCursor); + UserLists result = new UserLists(prevCursor, nextCursor); for (twitter4j.UserList list : lists) - result.add(new UserList(list, twitter.getId())); + result.add(new TwitterList(list, twitter.getId())); return result; } catch (Exception err) { throw new EngineException(err); @@ -971,9 +978,9 @@ public class TwitterEngine { * @return list information * @throws EngineException if access is unavailable */ - public UserList loadUserList(long listId) throws EngineException { + public TwitterList loadUserList(long listId) throws EngineException { try { - return new UserList(twitter.showUserList(listId), twitter.getId()); + return new TwitterList(twitter.showUserList(listId), twitter.getId()); } catch (Exception err) { throw new EngineException(err); } @@ -987,7 +994,7 @@ public class TwitterEngine { * @return List information * @throws EngineException if access is unavailable */ - public UserList followUserList(long listId, boolean follow) throws EngineException { + public TwitterList followUserList(long listId, boolean follow) throws EngineException { try { twitter4j.UserList list; if (follow) { @@ -995,7 +1002,7 @@ public class TwitterEngine { } else { list = twitter.destroyUserListSubscription(listId); } - return new UserList(list, twitter.getId(), follow); + return new TwitterList(list, twitter.getId(), follow); } catch (Exception err) { throw new EngineException(err); } @@ -1008,9 +1015,9 @@ public class TwitterEngine { * @return List information * @throws EngineException if access is unavailable */ - public UserList deleteUserList(long listId) throws EngineException { + public TwitterList deleteUserList(long listId) throws EngineException { try { - return new UserList(twitter.destroyUserList(listId), twitter.getId()); + return new TwitterList(twitter.destroyUserList(listId), twitter.getId()); } catch (Exception err) { throw new EngineException(err); } @@ -1023,12 +1030,12 @@ public class TwitterEngine { * @return list of users following the list * @throws EngineException if access is unavailable */ - public TwitterUserList getListFollower(long listId, long cursor) throws EngineException { + public UserList getListFollower(long listId, long cursor) throws EngineException { try { PagableResponseList followerList = twitter.getUserListSubscribers(listId, cursor); long prevCursor = cursor > 0 ? cursor : 0; long nextCursor = followerList.getNextCursor(); - TwitterUserList result = new TwitterUserList(prevCursor, nextCursor); + UserList result = new UserList(prevCursor, nextCursor); result.addAll(convertUserList(followerList)); return result; } catch (Exception err) { @@ -1043,12 +1050,12 @@ public class TwitterEngine { * @return list of users * @throws EngineException if access is unavailable */ - public TwitterUserList getListMember(long listId, long cursor) throws EngineException { + public UserList getListMember(long listId, long cursor) throws EngineException { try { PagableResponseList users = twitter.getUserListMembers(listId, cursor); long prevCursor = cursor > 0 ? cursor : 0; long nextCursor = users.getNextCursor(); - TwitterUserList result = new TwitterUserList(prevCursor, nextCursor); + UserList result = new UserList(prevCursor, nextCursor); result.addAll(convertUserList(users)); return result; } catch (Exception err) { @@ -1105,7 +1112,7 @@ public class TwitterEngine { * @param list holder for list information * @throws EngineException if access is unavailable */ - public UserList updateUserList(ListHolder list) throws EngineException { + public TwitterList updateUserList(ListHolder list) throws EngineException { try { twitter4j.UserList result; if (list.exists()) { @@ -1113,7 +1120,7 @@ public class TwitterEngine { } else { result = twitter.createUserList(list.getTitle(), list.isPublic(), list.getDescription()); } - return new UserList(result, twitter.getId()); + return new TwitterList(result, twitter.getId()); } catch (Exception err) { throw new EngineException(err); } diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/items/UserList.java b/app/src/main/java/org/nuclearfog/twidda/backend/items/TwitterList.java similarity index 91% rename from app/src/main/java/org/nuclearfog/twidda/backend/items/UserList.java rename to app/src/main/java/org/nuclearfog/twidda/backend/items/TwitterList.java index db516845..61a90b0e 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/items/UserList.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/items/TwitterList.java @@ -9,7 +9,7 @@ import java.io.Serializable; * * @author nuclearfog */ -public class UserList implements Serializable { +public class TwitterList implements Serializable { private long id; private long createdAt; @@ -28,7 +28,7 @@ public class UserList implements Serializable { * @param homeId ID of the authenticated user * @param isFollowing authenticated user is following list */ - public UserList(twitter4j.UserList list, long homeId, boolean isFollowing) { + public TwitterList(twitter4j.UserList list, long homeId, boolean isFollowing) { id = list.getId(); createdAt = list.getCreatedAt().getTime(); owner = new User(list.getUser(), homeId); @@ -42,7 +42,7 @@ public class UserList implements Serializable { this.isFollowing = isFollowing; } - public UserList(twitter4j.UserList list, long homeId) { + public TwitterList(twitter4j.UserList list, long homeId) { this(list, homeId, list.isFollowing()); } @@ -146,8 +146,8 @@ public class UserList implements Serializable { @Override public boolean equals(Object o) { - if (o instanceof UserList) - return ((UserList) o).id == id; + if (o instanceof TwitterList) + return ((TwitterList) o).id == id; return false; } } \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/lists/MessageList.java b/app/src/main/java/org/nuclearfog/twidda/backend/lists/MessageList.java new file mode 100644 index 00000000..f9190ee1 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/backend/lists/MessageList.java @@ -0,0 +1,108 @@ +package org.nuclearfog.twidda.backend.lists; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.nuclearfog.twidda.backend.items.Message; + +import java.util.LinkedList; + +/** + * Message list container class containing cursor information + * + * @author nuclearfog + */ +public class MessageList extends LinkedList { + + private String prevCursor, nextCursor; + + /** + * @param prevCursor cursor to a previous list + * @param nextCursor cursor to a next list + */ + public MessageList(String prevCursor, String nextCursor) { + super(); + this.prevCursor = prevCursor; + this.nextCursor = nextCursor; + } + + @Override + @Nullable + public Message get(int index) { + return super.get(index); + } + + /** + * replace old list with a new one + * + * @param list new list + */ + public void replaceAll(MessageList list) { + super.clear(); + super.addAll(list); + prevCursor = list.prevCursor; + nextCursor = list.nextCursor; + } + + /** + * add a new list to the bottom of this list + * + * @param list new list + * @param index Index of the sub list + */ + public void addAt(MessageList list, int index) { + super.addAll(index, list); + nextCursor = list.nextCursor; + } + + /** + * remove message item matching with a given ID + * + * @param id message ID + * @return index of the removed message or -1 if not found + */ + public int removeItem(long id) { + for (int index = 0; index < size(); index++) { + Message item = get(index); + if (item != null && item.getId() == id) { + remove(index); + return index; + } + } + return -1; + } + + /** + * get next cursor string + * + * @return cursor string + */ + public String getNextCursor() { + return nextCursor; + } + + /** + * check if this list has a previous cursor + * + * @return true if list has a previous cursor + */ + public boolean hasPrev() { + return prevCursor != null; + } + + /** + * check if this list has a cursor to a next list + * + * @return true if list has a next cursor + */ + public boolean hasNext() { + return nextCursor != null; + } + + + @Override + @NonNull + public String toString() { + return "size=" + size() + " pre=" + prevCursor + " pos=" + nextCursor; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/holder/TwitterUserList.java b/app/src/main/java/org/nuclearfog/twidda/backend/lists/UserList.java similarity index 60% rename from app/src/main/java/org/nuclearfog/twidda/backend/holder/TwitterUserList.java rename to app/src/main/java/org/nuclearfog/twidda/backend/lists/UserList.java index 7fdb8a67..55778b62 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/holder/TwitterUserList.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/lists/UserList.java @@ -1,6 +1,7 @@ -package org.nuclearfog.twidda.backend.holder; +package org.nuclearfog.twidda.backend.lists; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import org.nuclearfog.twidda.backend.items.User; @@ -11,12 +12,12 @@ import java.util.LinkedList; * * @author nuclearfog */ -public class TwitterUserList extends LinkedList { +public class UserList extends LinkedList { private long prevCursor = 0; private long nextCursor = 0; - public TwitterUserList() { + public UserList() { super(); } @@ -26,12 +27,35 @@ public class TwitterUserList extends LinkedList { * @param prevCursor previous cursor of the list * @param nextCursor next cursor of the list */ - public TwitterUserList(long prevCursor, long nextCursor) { + public UserList(long prevCursor, long nextCursor) { super(); this.prevCursor = prevCursor; this.nextCursor = nextCursor; } + @Nullable + @Override + public User get(int index) { + return super.get(index); + } + + /** + * remove user item from list matching screen name + * + * @param name screen name of the user + * @return index of the user item or -1 if not found + */ + public int removeItem(String name) { + for (int index = 0; index < size(); index++) { + User item = get(index); + if (item != null && item.getScreenname().equals(name)) { + remove(index); + return index; + } + } + return -1; + } + /** * check if list is linked to a previous list * @@ -59,42 +83,27 @@ public class TwitterUserList extends LinkedList { return nextCursor; } - /** - * get previous cursor - * - * @return previous cursor - */ - public long getPrev() { - return prevCursor; - } - /** * replace whole list including cursors * * @param list new list */ - public void replace(TwitterUserList list) { + public void replace(UserList list) { super.clear(); super.addAll(list); - prevCursor = list.getPrev(); - nextCursor = list.getNext(); + prevCursor = list.prevCursor; + nextCursor = list.nextCursor; } /** * add a sublist at the bottom of this list including next cursor * - * @param list new sublist + * @param list new sublist + * @param index index of the sub list */ - public void addListAt(TwitterUserList list, int index) { + public void addAt(UserList list, int index) { super.addAll(index, list); - nextCursor = list.getNext(); - } - - @Override - public void clear() { - prevCursor = 0; - nextCursor = 0; - super.clear(); + nextCursor = list.nextCursor; } @Override diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/holder/UserListList.java b/app/src/main/java/org/nuclearfog/twidda/backend/lists/UserLists.java similarity index 56% rename from app/src/main/java/org/nuclearfog/twidda/backend/holder/UserListList.java rename to app/src/main/java/org/nuclearfog/twidda/backend/lists/UserLists.java index ce6c4aeb..9bb39166 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/holder/UserListList.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/lists/UserLists.java @@ -1,8 +1,9 @@ -package org.nuclearfog.twidda.backend.holder; +package org.nuclearfog.twidda.backend.lists; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; -import org.nuclearfog.twidda.backend.items.UserList; +import org.nuclearfog.twidda.backend.items.TwitterList; import java.util.LinkedList; @@ -11,26 +12,34 @@ import java.util.LinkedList; * * @author nuclearfog */ -public class UserListList extends LinkedList { +public class UserLists extends LinkedList { - private long prevCursor = 0; - private long nextCursor = 0; + private long prevCursor, nextCursor; - public UserListList() { - super(); + /** + * create an empty list + */ + public UserLists() { + this(0, 0); } - /** * @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) { + public UserLists(long prevCursor, long nextCursor) { super(); this.prevCursor = prevCursor; this.nextCursor = nextCursor; } + + @Nullable + @Override + public TwitterList get(int index) { + return super.get(index); + } + /** * check if list is linked to a previous list * @@ -49,15 +58,6 @@ public class UserListList extends LinkedList { return nextCursor != 0; } - /** - * get prev link to a list - * - * @return cursor - */ - public long getPrev() { - return prevCursor; - } - /** * get next link to a list * @@ -72,30 +72,39 @@ public class UserListList extends LinkedList { * * @param list new list */ - public void replace(UserListList list) { + public void replace(UserLists list) { super.clear(); super.addAll(list); - prevCursor = list.getPrev(); - nextCursor = list.getNext(); + prevCursor = list.prevCursor; + nextCursor = list.nextCursor; + } + + /** + * remove an item from list + * + * @param id ID of the item + * @return index of the removed item + */ + public int removeItem(long id) { + for (int index = 0; index < size(); index++) { + TwitterList item = get(index); + if (item != null && item.getId() == id) { + remove(index); + return index; + } + } + return -1; } /** * add a sublist at the bottom of this list including next cursor * * @param list new sublist - * @param index position where to insert at + * @param index Index of the sub list */ - public void addListAt(UserListList list, int index) { + public void addAt(UserLists list, int index) { super.addAll(index, list); - nextCursor = list.getNext(); - } - - @Override - public void clear() { - // resetting cursors - prevCursor = 0; - nextCursor = 0; - super.clear(); + nextCursor = list.nextCursor; } @Override diff --git a/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java b/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java index 4c11a7d5..b14c459d 100644 --- a/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java +++ b/app/src/main/java/org/nuclearfog/twidda/database/AppDatabase.java @@ -11,6 +11,7 @@ import org.nuclearfog.twidda.backend.items.Message; import org.nuclearfog.twidda.backend.items.Trend; import org.nuclearfog.twidda.backend.items.Tweet; import org.nuclearfog.twidda.backend.items.User; +import org.nuclearfog.twidda.backend.lists.MessageList; import java.util.LinkedList; import java.util.List; @@ -427,10 +428,10 @@ public class AppDatabase { * * @return list of direct messages */ - public List getMessages() { + public MessageList getMessages() { String[] args = {Integer.toString(limit)}; - - List result = new LinkedList<>(); + // TODO get next cursor from database + MessageList result = new MessageList(null, null); SQLiteDatabase db = getDbRead(); Cursor cursor = db.rawQuery(MESSAGE_QUERY, args); if (cursor.moveToFirst()) { diff --git a/app/src/main/java/org/nuclearfog/twidda/fragment/MessageFragment.java b/app/src/main/java/org/nuclearfog/twidda/fragment/MessageFragment.java index bbdcd2a1..bf3028a5 100644 --- a/app/src/main/java/org/nuclearfog/twidda/fragment/MessageFragment.java +++ b/app/src/main/java/org/nuclearfog/twidda/fragment/MessageFragment.java @@ -18,12 +18,11 @@ import org.nuclearfog.twidda.adapter.MessageAdapter.OnItemSelected; import org.nuclearfog.twidda.backend.MessageLoader; import org.nuclearfog.twidda.backend.engine.EngineException; import org.nuclearfog.twidda.backend.items.Message; +import org.nuclearfog.twidda.backend.lists.MessageList; import org.nuclearfog.twidda.backend.utils.DialogBuilder; import org.nuclearfog.twidda.backend.utils.DialogBuilder.OnDialogClick; import org.nuclearfog.twidda.backend.utils.ErrorHandler; -import java.util.List; - import static android.os.AsyncTask.Status.RUNNING; import static android.widget.Toast.LENGTH_SHORT; import static org.nuclearfog.twidda.activity.MessageEditor.KEY_DM_PREFIX; @@ -59,7 +58,7 @@ public class MessageFragment extends ListFragment implements OnItemSelected, OnD public void onStart() { super.onStart(); if (messageTask == null) { - load(MessageLoader.Action.DB); + load(MessageLoader.Action.DB, null); setRefresh(true); } } @@ -67,7 +66,7 @@ public class MessageFragment extends ListFragment implements OnItemSelected, OnD @Override protected void onReset() { - load(MessageLoader.Action.DB); + load(MessageLoader.Action.DB, null); setRefresh(true); } @@ -83,7 +82,7 @@ public class MessageFragment extends ListFragment implements OnItemSelected, OnD @Override protected void onReload() { if (messageTask != null && messageTask.getStatus() != RUNNING) { - load(MessageLoader.Action.LOAD); + load(MessageLoader.Action.LOAD, null); } } @@ -151,9 +150,19 @@ public class MessageFragment extends ListFragment implements OnItemSelected, OnD } + @Override + public boolean onFooterClick(String cursor) { + if (messageTask != null && messageTask.getStatus() != RUNNING) { + load(MessageLoader.Action.LOAD, cursor); + return true; + } + return false; + } + + @Override public void onConfirm(DialogBuilder.DialogType type) { - messageTask = new MessageLoader(this, MessageLoader.Action.DEL); + messageTask = new MessageLoader(this, MessageLoader.Action.DEL, null); messageTask.execute(deleteId); } @@ -162,8 +171,8 @@ public class MessageFragment extends ListFragment implements OnItemSelected, OnD * * @param data list of direct messages */ - public void setData(List data) { - adapter.replaceAll(data); + public void setData(MessageList data) { + adapter.setData(data); setRefresh(false); } @@ -198,8 +207,8 @@ public class MessageFragment extends ListFragment implements OnItemSelected, OnD * * @param action mode for loading or removing messages */ - private void load(MessageLoader.Action action) { - messageTask = new MessageLoader(this, action); + private void load(MessageLoader.Action action, String cursor) { + messageTask = new MessageLoader(this, action, cursor); messageTask.execute(); } } \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/fragment/TweetFragment.java b/app/src/main/java/org/nuclearfog/twidda/fragment/TweetFragment.java index 4b02af2a..bfc609ad 100644 --- a/app/src/main/java/org/nuclearfog/twidda/fragment/TweetFragment.java +++ b/app/src/main/java/org/nuclearfog/twidda/fragment/TweetFragment.java @@ -201,10 +201,12 @@ public class TweetFragment extends ListFragment implements TweetClickListener { @Override - public void onHolderClick(long sinceId, long maxId, int pos) { + public boolean onHolderClick(long sinceId, long maxId, int pos) { if (tweetTask != null && tweetTask.getStatus() != RUNNING) { load(sinceId, maxId, pos); + return true; } + return false; } /** diff --git a/app/src/main/java/org/nuclearfog/twidda/fragment/UserFragment.java b/app/src/main/java/org/nuclearfog/twidda/fragment/UserFragment.java index 3b14c352..7b2cb46f 100644 --- a/app/src/main/java/org/nuclearfog/twidda/fragment/UserFragment.java +++ b/app/src/main/java/org/nuclearfog/twidda/fragment/UserFragment.java @@ -16,8 +16,8 @@ import org.nuclearfog.twidda.backend.ListManager.ListManagerCallback; import org.nuclearfog.twidda.backend.UserLoader; import org.nuclearfog.twidda.backend.UserLoader.Type; import org.nuclearfog.twidda.backend.engine.EngineException; -import org.nuclearfog.twidda.backend.holder.TwitterUserList; import org.nuclearfog.twidda.backend.items.User; +import org.nuclearfog.twidda.backend.lists.UserList; import org.nuclearfog.twidda.backend.utils.DialogBuilder; import org.nuclearfog.twidda.backend.utils.DialogBuilder.OnDialogClick; import org.nuclearfog.twidda.backend.utils.ErrorHandler; @@ -197,10 +197,12 @@ public class UserFragment extends ListFragment implements UserClickListener, @Override - public void onFooterClick(long cursor) { + public boolean onFooterClick(long cursor) { if (userTask != null && userTask.getStatus() != RUNNING) { load(cursor); + return true; } + return false; } @@ -241,7 +243,7 @@ public class UserFragment extends ListFragment implements UserClickListener, * * @param data list of twitter users */ - public void setData(TwitterUserList data) { + public void setData(UserList data) { adapter.setData(data); setRefresh(false); } diff --git a/app/src/main/java/org/nuclearfog/twidda/fragment/UserListFragment.java b/app/src/main/java/org/nuclearfog/twidda/fragment/UserListFragment.java index e7fe0920..33bf9cef 100644 --- a/app/src/main/java/org/nuclearfog/twidda/fragment/UserListFragment.java +++ b/app/src/main/java/org/nuclearfog/twidda/fragment/UserListFragment.java @@ -11,9 +11,9 @@ import org.nuclearfog.twidda.adapter.ListAdapter; import org.nuclearfog.twidda.adapter.ListAdapter.ListClickListener; import org.nuclearfog.twidda.backend.ListLoader; import org.nuclearfog.twidda.backend.engine.EngineException; -import org.nuclearfog.twidda.backend.holder.UserListList; +import org.nuclearfog.twidda.backend.items.TwitterList; import org.nuclearfog.twidda.backend.items.User; -import org.nuclearfog.twidda.backend.items.UserList; +import org.nuclearfog.twidda.backend.lists.UserLists; import org.nuclearfog.twidda.backend.utils.ErrorHandler; import static android.os.AsyncTask.Status.RUNNING; @@ -135,8 +135,8 @@ public class UserListFragment extends ListFragment implements ListClickListener adapter.removeItem(removedListId); } else if (resultCode == RETURN_LIST_UPDATED) { Object result = data.getSerializableExtra(RESULT_UPDATE_LIST); - if (result instanceof UserList) { - UserList update = (UserList) result; + if (result instanceof TwitterList) { + TwitterList update = (TwitterList) result; adapter.updateItem(update); } } @@ -153,7 +153,7 @@ public class UserListFragment extends ListFragment implements ListClickListener @Override - public void onListClick(UserList listItem) { + public void onListClick(TwitterList listItem) { Intent listIntent = new Intent(requireContext(), ListDetail.class); listIntent.putExtra(KEY_LIST_DATA, listItem); startActivityForResult(listIntent, REQUEST_OPEN_LIST); @@ -187,7 +187,7 @@ public class UserListFragment extends ListFragment implements ListClickListener * * @param data List of Twitter list data */ - public void setData(UserListList data) { + public void setData(UserLists data) { adapter.setData(data); setRefresh(false); } diff --git a/app/src/main/res/layout/page_listdetail.xml b/app/src/main/res/layout/page_listdetail.xml index f1ffd697..75e4f49e 100644 --- a/app/src/main/res/layout/page_listdetail.xml +++ b/app/src/main/res/layout/page_listdetail.xml @@ -9,7 +9,7 @@ + android:layout_height="wrap_content" /> @@ -116,7 +116,7 @@ android:text="@string/userlist_create" app:layout_constraintBottom_toBottomOf="@+id/userlist_switch_text" app:layout_constraintEnd_toEndOf="@id/userlist_popup_background" - app:layout_constraintHorizontal_weight="2" + app:layout_constraintHorizontal_weight="3" app:layout_constraintStart_toEndOf="@+id/userlist_switch_text" app:layout_constraintTop_toTopOf="@+id/userlist_switch_text" /> diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index b180b719..8ed92b09 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -137,7 +137,7 @@ öffentlich Titel eingeben Beschreibung der Liste eingeben - Liste erstellen + erstellen Titel ist leer! Liste wurde aktualisiert Liste wurde erstellt @@ -145,7 +145,7 @@ Füge Nutzer zur Liste hinzu Neue Liste erstellen Liste bearbeiten - Liste aktualisieren + aktualisieren Nutzer von der Liste entfernen? Nutzer von der Liste entfernt! Nutzer von der Liste entfernen