From f4cd3c9a4d1efff2b395c4372283710594492088 Mon Sep 17 00:00:00 2001 From: M M Arif Date: Wed, 29 Sep 2021 11:29:39 +0200 Subject: [PATCH] Refactors and clean up (#979) Related #278 Co-authored-by: M M Arif Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/979 Co-authored-by: M M Arif Co-committed-by: M M Arif --- .../gitnex/adapters/ExploreIssuesAdapter.java | 162 ++++++---- .../adapters/ExploreRepositoriesAdapter.java | 204 ++++++++----- .../adapters/MyProfileFollowersAdapter.java | 157 ++++++---- .../adapters/MyProfileFollowingAdapter.java | 156 ++++++---- .../gitnex/adapters/NotificationsAdapter.java | 207 ++++++++----- .../fragments/ExploreIssuesFragment.java | 161 +++++----- .../ExplorePublicOrganizationsFragment.java | 8 +- .../ExploreRepositoriesFragment.java | 218 ++++++------- .../fragments/MyProfileFollowersFragment.java | 198 ++++++------ .../fragments/MyProfileFollowingFragment.java | 208 +++++++------ .../gitnex/fragments/MyProfileFragment.java | 5 +- .../fragments/NotificationsFragment.java | 288 ++++++++---------- .../gitnex/fragments/ReleasesFragment.java | 1 - .../fragments/profile/DetailFragment.java | 1 + .../fragments/profile/FollowersFragment.java | 12 +- .../fragments/profile/FollowingFragment.java | 13 +- .../profile/OrganizationsFragment.java | 12 +- .../profile/RepositoriesFragment.java | 12 +- .../profile/StarredRepositoriesFragment.java | 11 +- .../org/mian/gitnex/helpers/Constants.java | 7 +- .../helpers/InfiniteScrollListener.java | 92 ------ .../viewmodels/ProfileFollowersViewModel.java | 59 ---- .../viewmodels/ProfileFollowingViewModel.java | 59 ---- .../res/layout/fragment_notifications.xml | 4 +- app/src/main/res/layout/fragment_profile.xml | 171 +++++------ .../res/layout/fragment_profile_detail.xml | 8 + 26 files changed, 1214 insertions(+), 1220 deletions(-) delete mode 100644 app/src/main/java/org/mian/gitnex/helpers/InfiniteScrollListener.java delete mode 100644 app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java delete mode 100644 app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java diff --git a/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java index 5067a22c..a3615ceb 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ExploreIssuesAdapter.java @@ -1,5 +1,6 @@ package org.mian.gitnex.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.view.LayoutInflater; @@ -34,31 +35,69 @@ import java.util.Locale; * Author M M Arif */ -public class ExploreIssuesAdapter extends RecyclerView.Adapter { +public class ExploreIssuesAdapter extends RecyclerView.Adapter { - private final List searchedList; private final Context context; + private final int TYPE_LOAD = 0; + private List searchedList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; private final TinyDB tinyDb; public ExploreIssuesAdapter(List dataList, Context ctx) { - this.context = ctx; this.searchedList = dataList; this.tinyDb = TinyDB.getInstance(context); } - class SearchViewHolder extends RecyclerView.ViewHolder { + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if(viewType == TYPE_LOAD) { + return new ExploreIssuesAdapter.IssuesHolder(inflater.inflate(R.layout.list_issues, parent, false)); + } + else { + return new ExploreIssuesAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((ExploreIssuesAdapter.IssuesHolder) holder).bindData(searchedList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(searchedList.get(position).getTitle() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return searchedList.size(); + } + + class IssuesHolder extends RecyclerView.ViewHolder { private Issues issue; private final ImageView issueAssigneeAvatar; private final TextView issueTitle; private final TextView issueCreatedTime; private final TextView issueCommentsCount; - private SearchViewHolder(View itemView) { - + IssuesHolder(View itemView) { super(itemView); - issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar); issueTitle = itemView.findViewById(R.id.issueTitle); issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount); @@ -108,68 +147,79 @@ public class ExploreIssuesAdapter extends RecyclerView.Adapter" + issue.getRepository().getFull_name() + context.getResources().getString(R.string.hash) + issue.getNumber() + ""; - Locale locale = context.getResources().getConfiguration().locale; - String timeFormat = tinyDb.getString("dateFormat"); + issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + issue.getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY)); + issueCommentsCount.setText(String.valueOf(issue.getComments())); - PicassoService.getInstance(context).get() - .load(currentItem.getUser().getAvatar_url()) - .placeholder(R.drawable.loader_animated) - .transform(new RoundedTransformation(imgRadius, 0)) - .resize(120, 120) - .centerCrop() - .into(holder.issueAssigneeAvatar); - - String issueNumber_ = "" + currentItem.getRepository().getFull_name() + context.getResources().getString(R.string.hash) + currentItem.getNumber() + ""; - - holder.issue = currentItem; - holder.issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + currentItem.getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY)); - holder.issueCommentsCount.setText(String.valueOf(currentItem.getComments())); - - switch(timeFormat) { - case "pretty": { - PrettyTime prettyTime = new PrettyTime(locale); - String createdTime = prettyTime.format(currentItem.getCreated_at()); - holder.issueCreatedTime.setText(createdTime); - holder.issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(currentItem.getCreated_at()), context)); - break; - } - case "normal": { - DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); - String createdTime = formatter.format(currentItem.getCreated_at()); - holder.issueCreatedTime.setText(createdTime); - break; - } - case "normal1": { - DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); - String createdTime = formatter.format(currentItem.getCreated_at()); - holder.issueCreatedTime.setText(createdTime); - break; + switch(timeFormat) { + case "pretty": { + PrettyTime prettyTime = new PrettyTime(locale); + String createdTime = prettyTime.format(issue.getCreated_at()); + issueCreatedTime.setText(createdTime); + issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issue.getCreated_at()), context)); + break; + } + case "normal": { + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); + String createdTime = formatter.format(issue.getCreated_at()); + issueCreatedTime.setText(createdTime); + break; + } + case "normal1": { + DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); + String createdTime = formatter.format(issue.getCreated_at()); + issueCreatedTime.setText(createdTime); + break; + } } + } } - @Override - public int getItemCount() { - return searchedList.size(); + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } } + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + @SuppressLint("NotifyDataSetChanged") public void notifyDataChanged() { notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + searchedList = list; + notifyDataChanged(); } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java index 2afa3aa9..530ce80e 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ExploreRepositoriesAdapter.java @@ -1,5 +1,6 @@ package org.mian.gitnex.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.graphics.Typeface; @@ -40,19 +41,61 @@ import retrofit2.Callback; * Author M M Arif */ -public class ExploreRepositoriesAdapter extends RecyclerView.Adapter { +public class ExploreRepositoriesAdapter extends RecyclerView.Adapter { - private final List reposList; private final Context context; + private final int TYPE_LOAD = 0; + private List reposList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + private final TinyDB tinyDb; public ExploreRepositoriesAdapter(List dataList, Context ctx) { - this.context = ctx; this.reposList = dataList; + this.tinyDb = TinyDB.getInstance(context); } - static class ReposSearchViewHolder extends RecyclerView.ViewHolder { + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if(viewType == TYPE_LOAD) { + return new ExploreRepositoriesAdapter.RepositoriesHolder(inflater.inflate(R.layout.list_repositories, parent, false)); + } + else { + return new ExploreRepositoriesAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((ExploreRepositoriesAdapter.RepositoriesHolder) holder).bindData(reposList.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(reposList.get(position).getFullName() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return reposList.size(); + } + + class RepositoriesHolder extends RecyclerView.ViewHolder { private UserRepositories userRepositories; private final ImageView image; @@ -63,8 +106,7 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter { Context context = v.getContext(); - TinyDB tinyDb = TinyDB.getInstance(context); - Intent intent = new Intent(context, RepoDetailActivity.class); intent.putExtra("repoFullName", userRepositories.getFullName()); @@ -153,98 +193,104 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter list) { + reposList = list; + notifyDataChanged(); + } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowersAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowersAdapter.java index 19d5bd9c..eb3d4c5d 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowersAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowersAdapter.java @@ -1,5 +1,6 @@ package org.mian.gitnex.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.text.Html; @@ -22,79 +23,129 @@ import java.util.List; * Author M M Arif */ -public class MyProfileFollowersAdapter extends RecyclerView.Adapter { +public class MyProfileFollowersAdapter extends RecyclerView.Adapter { - private final List followersList; - private final Context context; + private final Context context; + private final int TYPE_LOAD = 0; + private List followersList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; - class FollowersViewHolder extends RecyclerView.ViewHolder { + public MyProfileFollowersAdapter(List dataList, Context ctx) { + this.context = ctx; + this.followersList = dataList; + } - private String userLoginId; + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if(viewType == TYPE_LOAD) { + return new MyProfileFollowersAdapter.FollowersHolder(inflater.inflate(R.layout.list_profile_followers_following, parent, false)); + } + else { + return new MyProfileFollowersAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } - private final ImageView userAvatar; - private final TextView userFullName; - private final TextView userName; + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } - private FollowersViewHolder(View itemView) { + if(getItemViewType(position) == TYPE_LOAD) { + ((MyProfileFollowersAdapter.FollowersHolder) holder).bindData(followersList.get(position)); + } + } - super(itemView); + @Override + public int getItemViewType(int position) { + if(followersList.get(position).getUsername() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } - userAvatar = itemView.findViewById(R.id.userAvatar); - userFullName = itemView.findViewById(R.id.userFullName); - userName = itemView.findViewById(R.id.userName); + @Override + public int getItemCount() { + return followersList.size(); + } - itemView.setOnClickListener(loginId -> { - Intent intent = new Intent(context, ProfileActivity.class); - intent.putExtra("username", userLoginId); - context.startActivity(intent); - }); + class FollowersHolder extends RecyclerView.ViewHolder { + private UserInfo userInfo; + private final ImageView userAvatar; + private final TextView userFullName; + private final TextView userName; - itemView.setOnLongClickListener(loginId -> { - AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); - return true; - }); - } - } + FollowersHolder(View itemView) { + super(itemView); - public MyProfileFollowersAdapter(Context ctx, List followersListMain) { + userAvatar = itemView.findViewById(R.id.userAvatar); + userFullName = itemView.findViewById(R.id.userFullName); + userName = itemView.findViewById(R.id.userName); - this.context = ctx; - this.followersList = followersListMain; - } + itemView.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); - @NonNull - @Override - public MyProfileFollowersAdapter.FollowersViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + itemView.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); + } - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_followers_following, parent, false); - return new FollowersViewHolder(v); - } + @SuppressLint("SetTextI18n") + void bindData(UserInfo userInfo) { + this.userInfo = userInfo; + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); - @Override - public void onBindViewHolder(@NonNull MyProfileFollowersAdapter.FollowersViewHolder holder, int position) { + if(!userInfo.getFullname().equals("")) { + userFullName.setText(Html.fromHtml(userInfo.getFullname())); + userName.setText(context.getResources().getString(R.string.usernameWithAt, userInfo.getUsername())); + } + else { + userFullName.setText(userInfo.getUsername()); + userName.setVisibility(View.GONE); + } - UserInfo currentItem = followersList.get(position); - int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + PicassoService.getInstance(context).get().load(userInfo.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(userAvatar); + } + } - holder.userLoginId = currentItem.getLogin(); + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } - if(!currentItem.getFullname().equals("")) { - holder.userFullName.setText(Html.fromHtml(currentItem.getFullname())); - holder.userName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername())); - } - else { - holder.userFullName.setText(currentItem.getUsername()); - holder.userName.setVisibility(View.GONE); - } + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } - PicassoService.getInstance(context).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(holder.userAvatar); - } + @SuppressLint("NotifyDataSetChanged") + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } - @Override - public int getItemCount() { - return followersList.size(); - } + public interface OnLoadMoreListener { + void onLoadMore(); + } + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + followersList = list; + notifyDataChanged(); + } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowingAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowingAdapter.java index edebe155..b0dd183b 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowingAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/MyProfileFollowingAdapter.java @@ -1,5 +1,6 @@ package org.mian.gitnex.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.text.Html; @@ -22,78 +23,127 @@ import java.util.List; * Author M M Arif */ -public class MyProfileFollowingAdapter extends RecyclerView.Adapter { +public class MyProfileFollowingAdapter extends RecyclerView.Adapter { - private final List followingList; - private final Context context; + private final Context context; + private final int TYPE_LOAD = 0; + private List followingList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; - class FollowingViewHolder extends RecyclerView.ViewHolder { + public MyProfileFollowingAdapter(List dataList, Context ctx) { + this.context = ctx; + this.followingList = dataList; + } - private String userLoginId; + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if(viewType == TYPE_LOAD) { + return new MyProfileFollowingAdapter.FollowingHolder(inflater.inflate(R.layout.list_profile_followers_following, parent, false)); + } + else { + return new MyProfileFollowingAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } - private final ImageView userAvatar; - private final TextView userFullName; - private final TextView userName; + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } - private FollowingViewHolder(View itemView) { + if(getItemViewType(position) == TYPE_LOAD) { + ((MyProfileFollowingAdapter.FollowingHolder) holder).bindData(followingList.get(position)); + } + } - super(itemView); + @Override + public int getItemViewType(int position) { + if(followingList.get(position).getUsername() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } - userAvatar = itemView.findViewById(R.id.userAvatar); - userFullName = itemView.findViewById(R.id.userFullName); - userName = itemView.findViewById(R.id.userName); + @Override + public int getItemCount() { + return followingList.size(); + } - itemView.setOnClickListener(loginId -> { - Intent intent = new Intent(context, ProfileActivity.class); - intent.putExtra("username", userLoginId); - context.startActivity(intent); - }); + class FollowingHolder extends RecyclerView.ViewHolder { + private UserInfo userInfo; + private final ImageView userAvatar; + private final TextView userFullName; + private final TextView userName; - itemView.setOnLongClickListener(loginId -> { - AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); - return true; - }); - } - } + FollowingHolder(View itemView) { + super(itemView); - public MyProfileFollowingAdapter(Context ctx, List followingListMain) { + userAvatar = itemView.findViewById(R.id.userAvatar); + userFullName = itemView.findViewById(R.id.userFullName); + userName = itemView.findViewById(R.id.userName); - this.context = ctx; - this.followingList = followingListMain; - } + itemView.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userInfo.getLogin()); + context.startActivity(intent); + }); - @NonNull - @Override - public MyProfileFollowingAdapter.FollowingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + itemView.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin())); + return true; + }); + } - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_followers_following, parent, false); - return new FollowingViewHolder(v); - } + @SuppressLint("SetTextI18n") + void bindData(UserInfo userInfo) { + this.userInfo = userInfo; + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); - @Override - public void onBindViewHolder(@NonNull MyProfileFollowingAdapter.FollowingViewHolder holder, int position) { + if(!userInfo.getFullname().equals("")) { + userFullName.setText(Html.fromHtml(userInfo.getFullname())); + userName.setText(context.getResources().getString(R.string.usernameWithAt, userInfo.getUsername())); + } + else { + userFullName.setText(userInfo.getUsername()); + userName.setVisibility(View.GONE); + } - UserInfo currentItem = followingList.get(position); - int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + PicassoService.getInstance(context).get().load(userInfo.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(userAvatar); + } + } - holder.userLoginId = currentItem.getLogin(); + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } - if(!currentItem.getFullname().equals("")) { - holder.userFullName.setText(Html.fromHtml(currentItem.getFullname())); - holder.userName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername())); - } - else { - holder.userFullName.setText(currentItem.getUsername()); - holder.userName.setVisibility(View.GONE); - } + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } - PicassoService.getInstance(context).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(holder.userAvatar); - } + @SuppressLint("NotifyDataSetChanged") + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } - @Override - public int getItemCount() { - return followingList.size(); - } + public interface OnLoadMoreListener { + void onLoadMore(); + } + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + public void updateList(List list) { + followingList = list; + notifyDataChanged(); + } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/NotificationsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/NotificationsAdapter.java index 7e00d1f9..c7dca257 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/NotificationsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/NotificationsAdapter.java @@ -1,5 +1,6 @@ package org.mian.gitnex.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -21,18 +22,21 @@ import java.util.List; /** * Author opyale + * Modified M M Arif */ -public class NotificationsAdapter extends RecyclerView.Adapter { +public class NotificationsAdapter extends RecyclerView.Adapter { private final Context context; - private final List notificationThreads; + private final int TYPE_LOAD = 0; + private List notificationThreads; private final OnMoreClickedListener onMoreClickedListener; private final OnNotificationClickedListener onNotificationClickedListener; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; private final TinyDB tinyDb; public NotificationsAdapter(Context context, List notificationThreads, OnMoreClickedListener onMoreClickedListener, OnNotificationClickedListener onNotificationClickedListener) { - this.tinyDb = TinyDB.getInstance(context); this.context = context; this.notificationThreads = notificationThreads; @@ -40,7 +44,46 @@ public class NotificationsAdapter extends RecyclerView.Adapter= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + if(getItemViewType(position) == TYPE_LOAD) { + ((NotificationsAdapter.NotificationsHolder) holder).bindData(notificationThreads.get(position)); + } + } + + @Override + public int getItemViewType(int position) { + if(notificationThreads.get(position).getSubject() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } + + @Override + public int getItemCount() { + return notificationThreads.size(); + } + + class NotificationsHolder extends RecyclerView.ViewHolder { private final LinearLayout frame; private final TextView subject; @@ -51,10 +94,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter" + context.getResources().getString(R.string.hash) + url.substring(url.lastIndexOf("/") + 1) + ""; - @Override - public void onBindViewHolder(@NonNull NotificationsViewHolder holder, int position) { + subject.setText(HtmlCompat.fromHtml(subjectId + " " + notificationThread.getSubject().getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY)); + repository.setText(notificationThread.getRepository().getFullName()); - NotificationThread notificationThread = notificationThreads.get(position); - - String url = notificationThread.getSubject().getUrl(); - String subjectId = "" + context.getResources() - .getString(R.string.hash) + url.substring(url.lastIndexOf("/") + 1) + ""; - - holder.subject.setText(HtmlCompat.fromHtml(subjectId + " " + notificationThread.getSubject().getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY)); - holder.repository.setText(notificationThread.getRepository().getFullName()); - - if(notificationThread.isPinned()) { - holder.pinned.setVisibility(View.VISIBLE); - } else { - holder.pinned.setVisibility(View.GONE); - } - - switch(notificationThread.getSubject().getType()) { - - case "Pull": - holder.typePr.setVisibility(View.VISIBLE); - holder.typeIssue.setVisibility(View.GONE); - holder.typeUnknown.setVisibility(View.GONE); - break; - - case "Issue": - holder.typePr.setVisibility(View.GONE); - holder.typeIssue.setVisibility(View.VISIBLE); - holder.typeUnknown.setVisibility(View.GONE); - break; - - default: - holder.typePr.setVisibility(View.GONE); - holder.typeIssue.setVisibility(View.GONE); - holder.typeUnknown.setVisibility(View.VISIBLE); - break; - - } - - holder.frame.setOnClickListener(v -> { - - onNotificationClickedListener.onNotificationClicked(notificationThread); - - String[] parts = notificationThread.getRepository().getFullName().split("/"); - final String repoOwner = parts[0]; - final String repoName = parts[1]; - - int currentActiveAccountId = tinyDb.getInt("currentActiveAccountId"); - RepositoriesApi repositoryData = BaseApi.getInstance(context, RepositoriesApi.class); - - Integer count = repositoryData.checkRepository(currentActiveAccountId, repoOwner, repoName); - - if(count == 0) { - long id = repositoryData.insertRepository(currentActiveAccountId, repoOwner, repoName); - tinyDb.putLong("repositoryId", id); - } else { - Repository data = repositoryData.getRepository(currentActiveAccountId, repoOwner, repoName); - tinyDb.putLong("repositoryId", data.getRepositoryId()); + if(notificationThread.isPinned()) { + pinned.setVisibility(View.VISIBLE); + } + else { + pinned.setVisibility(View.GONE); } - }); - holder.more.setOnClickListener(v -> onMoreClickedListener.onMoreClicked(notificationThread)); + switch(notificationThread.getSubject().getType()) { + case "Pull": + typePr.setVisibility(View.VISIBLE); + typeIssue.setVisibility(View.GONE); + typeUnknown.setVisibility(View.GONE); + break; + case "Issue": + typePr.setVisibility(View.GONE); + typeIssue.setVisibility(View.VISIBLE); + typeUnknown.setVisibility(View.GONE); + break; + default: + typePr.setVisibility(View.GONE); + typeIssue.setVisibility(View.GONE); + typeUnknown.setVisibility(View.VISIBLE); + break; + } + + frame.setOnClickListener(v -> { + + onNotificationClickedListener.onNotificationClicked(notificationThread); + + String[] parts = notificationThread.getRepository().getFullName().split("/"); + final String repoOwner = parts[0]; + final String repoName = parts[1]; + + int currentActiveAccountId = tinyDb.getInt("currentActiveAccountId"); + RepositoriesApi repositoryData = BaseApi.getInstance(context, RepositoriesApi.class); + + Integer count = repositoryData.checkRepository(currentActiveAccountId, repoOwner, repoName); + + if(count == 0) { + long id = repositoryData.insertRepository(currentActiveAccountId, repoOwner, repoName); + tinyDb.putLong("repositoryId", id); + } + else { + Repository data = repositoryData.getRepository(currentActiveAccountId, repoOwner, repoName); + tinyDb.putLong("repositoryId", data.getRepositoryId()); + } + }); + + more.setOnClickListener(v -> onMoreClickedListener.onMoreClicked(notificationThread)); + } } - @Override - public int getItemCount() { + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } - return notificationThreads.size(); + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + } + + @SuppressLint("NotifyDataSetChanged") + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + } + + public interface OnLoadMoreListener { + void onLoadMore(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + notificationThreads = list; + notifyDataChanged(); } public interface OnNotificationClickedListener { - void onNotificationClicked(NotificationThread notificationThread); } public interface OnMoreClickedListener { - void onMoreClicked(NotificationThread notificationThread); } - } diff --git a/app/src/main/java/org/mian/gitnex/fragments/ExploreIssuesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ExploreIssuesFragment.java index 47b414c4..38b90855 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ExploreIssuesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ExploreIssuesFragment.java @@ -2,6 +2,8 @@ package org.mian.gitnex.fragments; import android.content.Context; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -13,12 +15,13 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import org.gitnex.tea4j.models.Issues; +import org.mian.gitnex.R; import org.mian.gitnex.adapters.ExploreIssuesAdapter; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentSearchIssuesBinding; -import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.Authorization; -import org.mian.gitnex.helpers.InfiniteScrollListener; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -33,30 +36,22 @@ import retrofit2.Response; public class ExploreIssuesFragment extends Fragment { private FragmentSearchIssuesBinding viewBinding; - private ExploreIssuesAdapter adapter; - private List dataList; - Context ctx; + private Context context; - private int apiCallCurrentValue = 10; - private int pageCurrentIndex = 1; + private List dataList; + private ExploreIssuesAdapter adapter; + private int pageSize; + private final String TAG = Constants.exploreIssues; + private final int resultLimit = Constants.resultLimitOldGiteaInstances; // search issues always return 10 records @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { viewBinding = FragmentSearchIssuesBinding.inflate(inflater, container, false); - setHasOptionsMenu(true); - ctx = getContext(); + context = getContext(); dataList = new ArrayList<>(); - adapter = new ExploreIssuesAdapter(dataList, ctx); - - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx); - - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(viewBinding.recyclerViewSearchIssues.getContext(), DividerItemDecoration.VERTICAL); - viewBinding.recyclerViewSearchIssues.addItemDecoration(dividerItemDecoration); - viewBinding.recyclerViewSearchIssues.setHasFixedSize(true); - viewBinding.recyclerViewSearchIssues.setLayoutManager(linearLayoutManager); - viewBinding.recyclerViewSearchIssues.setAdapter(adapter); + adapter = new ExploreIssuesAdapter(dataList, context); viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> { if(actionId == EditorInfo.IME_ACTION_SEND) { @@ -64,87 +59,111 @@ public class ExploreIssuesFragment extends Fragment { InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(viewBinding.searchKeyword.getWindowToken(), 0); - pageCurrentIndex = 1; - apiCallCurrentValue = 10; viewBinding.progressBar.setVisibility(View.VISIBLE); - loadData(false, viewBinding.searchKeyword.getText().toString()); + loadInitial(String.valueOf(viewBinding.searchKeyword.getText()), resultLimit); + + adapter.setLoadMoreListener(() -> viewBinding.recyclerViewSearchIssues.post(() -> { + if(dataList.size() == resultLimit || pageSize == resultLimit) { + int page = (dataList.size() + resultLimit) / resultLimit; + loadMore(String.valueOf(viewBinding.searchKeyword.getText()), resultLimit, page); + } + })); } } return false; }); - viewBinding.recyclerViewSearchIssues.addOnScrollListener(new InfiniteScrollListener(pageCurrentIndex, linearLayoutManager) { - @Override - public void onScrolledToEnd(int firstVisibleItemPosition) { - pageCurrentIndex++; - loadData(true, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString()); + viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + viewBinding.pullToRefresh.setRefreshing(false); + loadInitial("", resultLimit); + adapter.notifyDataChanged(); + }, 200)); + + adapter.setLoadMoreListener(() -> viewBinding.recyclerViewSearchIssues.post(() -> { + if(dataList.size() == resultLimit || pageSize == resultLimit) { + int page = (dataList.size() + resultLimit) / resultLimit; + loadMore(String.valueOf(viewBinding.searchKeyword.getText()), resultLimit, page); } - }); + })); - viewBinding.pullToRefresh.setOnRefreshListener(() -> { - pageCurrentIndex = 1; - apiCallCurrentValue = 10; - loadData(false, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString()); - }); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + viewBinding.recyclerViewSearchIssues.setHasFixedSize(true); + viewBinding.recyclerViewSearchIssues.addItemDecoration(dividerItemDecoration); + viewBinding.recyclerViewSearchIssues.setLayoutManager(new LinearLayoutManager(context)); + viewBinding.recyclerViewSearchIssues.setAdapter(adapter); - loadData(false, ""); + loadInitial("", resultLimit); return viewBinding.getRoot(); } - private void loadData(boolean append, String searchKeyword) { - - viewBinding.noData.setVisibility(View.GONE); - - int apiCallDefaultLimit = 10; - if(apiCallDefaultLimit > apiCallCurrentValue) { - return; - } - - if(pageCurrentIndex == 1 || !append) { - dataList.clear(); - adapter.notifyDataSetChanged(); - viewBinding.pullToRefresh.setRefreshing(false); - viewBinding.progressBar.setVisibility(View.VISIBLE); - } - else { - viewBinding.loadingMoreView.setVisibility(View.VISIBLE); - } - - Call> call = RetrofitClient.getApiInterface(getContext()) - .queryIssues(Authorization.get(getContext()), searchKeyword, "issues", "open", pageCurrentIndex); + private void loadInitial(String searchKeyword, int resultLimit) { + Call> call = RetrofitClient + .getApiInterface(context).queryIssues(Authorization.get(getContext()), searchKeyword, "issues", "open", resultLimit, 1); call.enqueue(new Callback>() { @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if(response.code() == 200) { - assert response.body() != null; - apiCallCurrentValue = response.body().size(); - if(!append) { + if(response.isSuccessful()) { + if(response.body() != null && response.body().size() > 0) { dataList.clear(); + dataList.addAll(response.body()); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.GONE); } - dataList.addAll(response.body()); - adapter.notifyDataSetChanged(); + else { + dataList.clear(); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.VISIBLE); + } + viewBinding.progressBar.setVisibility(View.GONE); + } + else if(response.code() == 404) { + viewBinding.noData.setVisibility(View.VISIBLE); + viewBinding.progressBar.setVisibility(View.GONE); } else { - dataList.clear(); - adapter.notifyDataChanged(); - viewBinding.noData.setVisibility(View.VISIBLE); + Log.e(TAG, String.valueOf(response.code())); } - onCleanup(); } @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.e("onFailure", Objects.requireNonNull(t.getMessage())); - onCleanup(); + Log.e(TAG, t.toString()); + } + }); + } + + private void loadMore(String searchKeyword, int resultLimit, int page) { + + viewBinding.loadingMoreView.setVisibility(View.VISIBLE); + Call> call = RetrofitClient.getApiInterface(context) + .queryIssues(Authorization.get(getContext()), searchKeyword, "issues", "open", resultLimit, page); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.isSuccessful()) { + assert response.body() != null; + List result = response.body(); + if(result.size() > 0) { + pageSize = result.size(); + dataList.addAll(result); + } + else { + SnackBar.info(context, viewBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + viewBinding.loadingMoreView.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } } - private void onCleanup() { - AppUtil.setMultiVisibility(View.GONE, viewBinding.loadingMoreView, viewBinding.progressBar); - if(dataList.isEmpty()) { - viewBinding.noData.setVisibility(View.VISIBLE); - } + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); } }); } diff --git a/app/src/main/java/org/mian/gitnex/fragments/ExplorePublicOrganizationsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ExplorePublicOrganizationsFragment.java index 27a60b71..6733f5c8 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ExplorePublicOrganizationsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ExplorePublicOrganizationsFragment.java @@ -22,7 +22,6 @@ import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.TinyDB; -import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; import retrofit2.Call; @@ -41,7 +40,7 @@ public class ExplorePublicOrganizationsFragment extends Fragment { private Context context; private int pageSize; private final String TAG = Constants.publicOrganizations; - private int resultLimit = Constants.resultLimitOldGiteaInstances; + private int resultLimit; @Nullable @Override @@ -54,10 +53,7 @@ public class ExplorePublicOrganizationsFragment extends Fragment { final String loginUid = tinyDb.getString("loginUid"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - resultLimit = Constants.resultLimitNewGiteaInstances; - } + resultLimit = Constants.getCurrentResultLimit(context); fragmentPublicOrgBinding.addNewOrganization.setVisibility(View.GONE); organizationsList = new ArrayList<>(); diff --git a/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java index 980edc01..5e8013df 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ExploreRepositoriesFragment.java @@ -6,6 +6,8 @@ import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -26,12 +28,10 @@ import org.mian.gitnex.adapters.ExploreRepositoriesAdapter; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.CustomExploreRepositoriesDialogBinding; import org.mian.gitnex.databinding.FragmentExploreRepoBinding; -import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; -import org.mian.gitnex.helpers.InfiniteScrollListener; +import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.TinyDB; -import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -42,19 +42,21 @@ import retrofit2.Response; /** * Template Author M M Arif * Author 6543 + * Modified M M Arif */ public class ExploreRepositoriesFragment extends Fragment { private FragmentExploreRepoBinding viewBinding; - private Context ctx; + private Context context; private TinyDB tinyDb; - private int pageCurrentIndex = 1; - private boolean repoTypeInclude = true; - private String sort = "updated"; - private String order = "desc"; - private int limit = 10; + private int pageSize; + private final boolean repoTypeInclude = true; + private final String sort = "updated"; + private final String order = "desc"; + private final String TAG = Constants.exploreRepositories; + private int resultLimit; private List dataList; private ExploreRepositoriesAdapter adapter; @@ -67,164 +69,130 @@ public class ExploreRepositoriesFragment extends Fragment { viewBinding = FragmentExploreRepoBinding.inflate(inflater, container, false); setHasOptionsMenu(true); - ctx = getContext(); + context = getContext(); tinyDb = TinyDB.getInstance(getContext()); dataList = new ArrayList<>(); - adapter = new ExploreRepositoriesAdapter(dataList, ctx); + adapter = new ExploreRepositoriesAdapter(dataList, context); tinyDb.putBoolean("exploreRepoIncludeTopic", false); tinyDb.putBoolean("exploreRepoIncludeDescription", false); tinyDb.putBoolean("exploreRepoIncludeTemplate", false); tinyDb.putBoolean("exploreRepoOnlyArchived", false); - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - limit = Constants.resultLimitNewGiteaInstances; - } - - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ctx); - - viewBinding.recyclerViewReposSearch.setHasFixedSize(true); - viewBinding.recyclerViewReposSearch.setLayoutManager(linearLayoutManager); - viewBinding.recyclerViewReposSearch.setAdapter(adapter); - - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(viewBinding.recyclerViewReposSearch.getContext(), - DividerItemDecoration.VERTICAL); - viewBinding.recyclerViewReposSearch.addItemDecoration(dividerItemDecoration); + resultLimit = Constants.getCurrentResultLimit(context); viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> { - if(actionId == EditorInfo.IME_ACTION_SEND) { - if(!Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString().equals("")) { - InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(viewBinding.searchKeyword.getWindowToken(), 0); - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - limit = Constants.resultLimitNewGiteaInstances; - } - else { - limit = 10; - } - - pageCurrentIndex = 1; viewBinding.progressBar.setVisibility(View.VISIBLE); - loadData(false, viewBinding.searchKeyword.getText().toString(), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived")); + loadInitial(String.valueOf(viewBinding.searchKeyword.getText()), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"), resultLimit); + + adapter.setLoadMoreListener(() -> viewBinding.recyclerViewReposSearch.post(() -> { + if(dataList.size() == resultLimit || pageSize == resultLimit) { + int page = (dataList.size() + resultLimit) / resultLimit; + loadMore(String.valueOf(viewBinding.searchKeyword.getText()), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"), resultLimit, page); + } + })); } } return false; }); - viewBinding.recyclerViewReposSearch.addOnScrollListener(new InfiniteScrollListener(pageCurrentIndex, linearLayoutManager) { + viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + viewBinding.pullToRefresh.setRefreshing(false); + loadInitial("", tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"), resultLimit); + adapter.notifyDataChanged(); + }, 200)); - @Override - public void onScrolledToEnd(int firstVisibleItemPosition) { - - pageCurrentIndex++; - loadData(true, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString(), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived")); + adapter.setLoadMoreListener(() -> viewBinding.recyclerViewReposSearch.post(() -> { + if(dataList.size() == resultLimit || pageSize == resultLimit) { + int page = (dataList.size() + resultLimit) / resultLimit; + loadMore(String.valueOf(viewBinding.searchKeyword.getText()), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"), resultLimit, page); } - }); + })); - viewBinding.pullToRefresh.setOnRefreshListener(() -> { + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + viewBinding.recyclerViewReposSearch.setHasFixedSize(true); + viewBinding.recyclerViewReposSearch.addItemDecoration(dividerItemDecoration); + viewBinding.recyclerViewReposSearch.setLayoutManager(new LinearLayoutManager(context)); + viewBinding.recyclerViewReposSearch.setAdapter(adapter); - pageCurrentIndex = 1; - - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - limit = Constants.resultLimitNewGiteaInstances; - } - else { - limit = 10; - } - - loadData(false, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString(), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived")); - }); - - loadData(false, "", tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived")); + loadInitial("", tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"), resultLimit); return viewBinding.getRoot(); - } - private void loadData(boolean append, String searchKeyword, boolean exploreRepoIncludeTopic, boolean exploreRepoIncludeDescription, boolean exploreRepoIncludeTemplate, boolean exploreRepoOnlyArchived) { - - viewBinding.noData.setVisibility(View.GONE); - - int apiCallDefaultLimit = 10; - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - apiCallDefaultLimit = Constants.resultLimitNewGiteaInstances; - } - - if(apiCallDefaultLimit > limit) { - return; - } - - if(pageCurrentIndex == 1 || !append) { - - dataList.clear(); - adapter.notifyDataSetChanged(); - viewBinding.pullToRefresh.setRefreshing(false); - viewBinding.progressBar.setVisibility(View.VISIBLE); - } - else { - - viewBinding.loadingMoreView.setVisibility(View.VISIBLE); - } - - Call call = RetrofitClient.getApiInterface(ctx).queryRepos(Authorization.get(getContext()), searchKeyword, repoTypeInclude, sort, order, exploreRepoIncludeTopic, exploreRepoIncludeDescription, exploreRepoIncludeTemplate, exploreRepoOnlyArchived, limit, pageCurrentIndex); + private void loadInitial(String searchKeyword, boolean exploreRepoIncludeTopic, boolean exploreRepoIncludeDescription, boolean exploreRepoIncludeTemplate, boolean exploreRepoOnlyArchived, int resultLimit) { + Call call = RetrofitClient + .getApiInterface(context).queryRepos(Authorization.get(getContext()), searchKeyword, repoTypeInclude, sort, order, exploreRepoIncludeTopic, exploreRepoIncludeDescription, exploreRepoIncludeTemplate, exploreRepoOnlyArchived, resultLimit, 1); call.enqueue(new Callback() { - @Override public void onResponse(@NonNull Call call, @NonNull Response response) { - - if(response.code() == 200) { - - assert response.body() != null; - - limit = response.body().getSearchedData().size(); - - if(!append) { - + if(response.isSuccessful()) { + if(response.body() != null && response.body().getSearchedData().size() > 0) { dataList.clear(); + dataList.addAll(response.body().getSearchedData()); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.GONE); } - - dataList.addAll(response.body().getSearchedData()); - adapter.notifyDataSetChanged(); - + else { + dataList.clear(); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.VISIBLE); + } + viewBinding.progressBar.setVisibility(View.GONE); + } + else if(response.code() == 404) { + viewBinding.noData.setVisibility(View.VISIBLE); + viewBinding.progressBar.setVisibility(View.GONE); } else { - - dataList.clear(); - adapter.notifyDataChanged(); - viewBinding.noData.setVisibility(View.VISIBLE); - + Log.e(TAG, String.valueOf(response.code())); } - - onCleanup(); - } @Override public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + } + }); + } - Log.e("onFailure", Objects.requireNonNull(t.getMessage())); - onCleanup(); + private void loadMore(String searchKeyword, boolean exploreRepoIncludeTopic, boolean exploreRepoIncludeDescription, boolean exploreRepoIncludeTemplate, boolean exploreRepoOnlyArchived, int resultLimit, int page) { + viewBinding.loadingMoreView.setVisibility(View.VISIBLE); + Call call = RetrofitClient.getApiInterface(context) + .queryRepos(Authorization.get(getContext()), searchKeyword, repoTypeInclude, sort, order, exploreRepoIncludeTopic, exploreRepoIncludeDescription, exploreRepoIncludeTemplate, exploreRepoOnlyArchived, resultLimit, page); + call.enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if(response.isSuccessful()) { + assert response.body() != null; + List result = response.body().getSearchedData(); + if(result.size() > 0) { + pageSize = result.size(); + dataList.addAll(result); + } + else { + SnackBar.info(context, viewBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + viewBinding.loadingMoreView.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } } - private void onCleanup() { - - AppUtil.setMultiVisibility(View.GONE, viewBinding.loadingMoreView, viewBinding.progressBar); - - if(dataList.isEmpty()) { - - viewBinding.noData.setVisibility(View.VISIBLE); - } + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); } }); } @@ -235,7 +203,6 @@ public class ExploreRepositoriesFragment extends Fragment { menu.clear(); inflater.inflate(R.menu.filter_menu, menu); super.onCreateOptionsMenu(menu, inflater); - MenuItem filter = menu.findItem(R.id.filter); filter.setOnMenuItemClickListener(filter_ -> { @@ -243,19 +210,17 @@ public class ExploreRepositoriesFragment extends Fragment { showFilterOptions(); return false; }); - } private void showFilterOptions() { - dialogFilterOptions = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert); + dialogFilterOptions = new Dialog(context, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert); if (dialogFilterOptions.getWindow() != null) { - dialogFilterOptions.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); } - filterBinding = CustomExploreRepositoriesDialogBinding.inflate(LayoutInflater.from(ctx)); + filterBinding = CustomExploreRepositoriesDialogBinding.inflate(LayoutInflater.from(context)); View view = filterBinding.getRoot(); dialogFilterOptions.setContentView(view); @@ -290,13 +255,10 @@ public class ExploreRepositoriesFragment extends Fragment { @Override public void onDetach() { - super.onDetach(); } public interface OnFragmentInteractionListener { - void onFragmentInteraction(Uri uri); } - } diff --git a/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowersFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowersFragment.java index 4f42ec81..4688a2b8 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowersFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowersFragment.java @@ -1,25 +1,30 @@ package org.mian.gitnex.fragments; -import android.net.Uri; +import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import org.gitnex.tea4j.models.UserInfo; +import org.mian.gitnex.R; import org.mian.gitnex.adapters.MyProfileFollowersAdapter; +import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; import org.mian.gitnex.helpers.Authorization; -import org.mian.gitnex.viewmodels.ProfileFollowersViewModel; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; /** * Author M M Arif @@ -27,106 +32,119 @@ import org.mian.gitnex.viewmodels.ProfileFollowersViewModel; public class MyProfileFollowersFragment extends Fragment { - private ProgressBar mProgressBar; - private MyProfileFollowersAdapter adapter; - private RecyclerView mRecyclerView; - private TextView noDataFollowers; - private static String repoNameF = "param2"; - private static String repoOwnerF = "param1"; + private FragmentProfileFollowersFollowingBinding viewBinding; + private Context context; - private String repoName; - private String repoOwner; - - private OnFragmentInteractionListener mListener; - - public MyProfileFollowersFragment() { - } - - public static MyProfileFollowersFragment newInstance(String param1, String param2) { - MyProfileFollowersFragment fragment = new MyProfileFollowersFragment(); - Bundle args = new Bundle(); - args.putString(repoOwnerF, param1); - args.putString(repoNameF, param2); - fragment.setArguments(args); - return fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - repoName = getArguments().getString(repoNameF); - repoOwner = getArguments().getString(repoOwnerF); - } - } + private List dataList; + private MyProfileFollowersAdapter adapter; + private int pageSize; + private final String TAG = Constants.tagFollowers; + private int resultLimit; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - FragmentProfileFollowersFollowingBinding fragmentProfileFollowersFollowingBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); + viewBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); + context = getContext(); - final SwipeRefreshLayout swipeRefresh = fragmentProfileFollowersFollowingBinding.pullToRefresh; + dataList = new ArrayList<>(); + adapter = new MyProfileFollowersAdapter(dataList, context); + resultLimit = Constants.getCurrentResultLimit(context); - noDataFollowers = fragmentProfileFollowersFollowingBinding.noData; - mRecyclerView = fragmentProfileFollowersFollowingBinding.recyclerView; + viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + viewBinding.pullToRefresh.setRefreshing(false); + loadInitial(resultLimit); + adapter.notifyDataChanged(); + }, 200)); - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL); + adapter.setLoadMoreListener(() -> viewBinding.recyclerView.post(() -> { + if(dataList.size() == resultLimit || pageSize == resultLimit) { + int page = (dataList.size() + resultLimit) / resultLimit; + loadMore(resultLimit, page); + } + })); - mRecyclerView.setHasFixedSize(true); - mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - mRecyclerView.addItemDecoration(dividerItemDecoration); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + viewBinding.recyclerView.setHasFixedSize(true); + viewBinding.recyclerView.addItemDecoration(dividerItemDecoration); + viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + viewBinding.recyclerView.setAdapter(adapter); - mProgressBar = fragmentProfileFollowersFollowingBinding.progressBar; + loadInitial(resultLimit); - swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { - - swipeRefresh.setRefreshing(false); - ProfileFollowersViewModel.loadFollowersList(Authorization.get(getContext()), getContext()); - - }, 200)); - - fetchDataAsync(Authorization.get(getContext())); - - return fragmentProfileFollowersFollowingBinding.getRoot(); + return viewBinding.getRoot(); } - private void fetchDataAsync(String instanceToken) { + private void loadInitial(int resultLimit) { - ProfileFollowersViewModel pfModel = new ViewModelProvider(this).get(ProfileFollowersViewModel.class); + Call> call = RetrofitClient + .getApiInterface(context) + .getFollowers(Authorization.get(getContext()), 1, resultLimit); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.isSuccessful()) { + if(response.body() != null && response.body().size() > 0) { + dataList.clear(); + dataList.addAll(response.body()); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.GONE); + } + else { + dataList.clear(); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.VISIBLE); + } + viewBinding.progressBar.setVisibility(View.GONE); + } + else if(response.code() == 404) { + viewBinding.noData.setVisibility(View.VISIBLE); + viewBinding.progressBar.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } + } - pfModel.getFollowersList(instanceToken, getContext()).observe(getViewLifecycleOwner(), pfListMain -> { + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + } + }); + } - adapter = new MyProfileFollowersAdapter(getContext(), pfListMain); + private void loadMore(int resultLimit, int page) { - if(adapter.getItemCount() > 0) { - mRecyclerView.setAdapter(adapter); - noDataFollowers.setVisibility(View.GONE); - } - else { - adapter.notifyDataSetChanged(); - mRecyclerView.setAdapter(adapter); - noDataFollowers.setVisibility(View.VISIBLE); - } + viewBinding.progressLoadMore.setVisibility(View.VISIBLE); + Call> call = RetrofitClient.getApiInterface(context) + .getFollowers(Authorization.get(getContext()), page, resultLimit); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.isSuccessful()) { + assert response.body() != null; + List result = response.body(); + if(result.size() > 0) { + pageSize = result.size(); + dataList.addAll(result); + } + else { + SnackBar.info(context, viewBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + viewBinding.progressLoadMore.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } + } - mProgressBar.setVisibility(View.GONE); - }); - - } - - public void onButtonPressed(Uri uri) { - if (mListener != null) { - mListener.onFragmentInteraction(uri); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - public interface OnFragmentInteractionListener { - void onFragmentInteraction(Uri uri); - } + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + } + }); + } } diff --git a/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowingFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowingFragment.java index 5aa9ce13..6d70df08 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowingFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFollowingFragment.java @@ -1,26 +1,30 @@ package org.mian.gitnex.fragments; -import android.net.Uri; +import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import org.gitnex.tea4j.models.UserInfo; +import org.mian.gitnex.R; import org.mian.gitnex.adapters.MyProfileFollowingAdapter; +import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; import org.mian.gitnex.helpers.Authorization; -import org.mian.gitnex.helpers.TinyDB; -import org.mian.gitnex.viewmodels.ProfileFollowingViewModel; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.SnackBar; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; /** * Author M M Arif @@ -28,108 +32,118 @@ import org.mian.gitnex.viewmodels.ProfileFollowingViewModel; public class MyProfileFollowingFragment extends Fragment { - private ProgressBar mProgressBar; - private MyProfileFollowingAdapter adapter; - private RecyclerView mRecyclerView; - private TextView noDataFollowing; - private static final String repoNameF = "param2"; - private static final String repoOwnerF = "param1"; + private FragmentProfileFollowersFollowingBinding viewBinding; + private Context context; - private String repoName; - private String repoOwner; + private List dataList; + private MyProfileFollowingAdapter adapter; + private int pageSize; + private final String TAG = Constants.tagFollowing; + private int resultLimit; - private OnFragmentInteractionListener mListener; + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - public MyProfileFollowingFragment() { - } + viewBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); + context = getContext(); - public static MyProfileFollowingFragment newInstance(String param1, String param2) { - MyProfileFollowingFragment fragment = new MyProfileFollowingFragment(); - Bundle args = new Bundle(); - args.putString(repoOwnerF, param1); - args.putString(repoNameF, param2); - fragment.setArguments(args); - return fragment; - } + dataList = new ArrayList<>(); + adapter = new MyProfileFollowingAdapter(dataList, context); + resultLimit = Constants.getCurrentResultLimit(context); - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getArguments() != null) { - repoName = getArguments().getString(repoNameF); - repoOwner = getArguments().getString(repoOwnerF); - } - } + viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + viewBinding.pullToRefresh.setRefreshing(false); + loadInitial(resultLimit); + adapter.notifyDataChanged(); + }, 200)); - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { + adapter.setLoadMoreListener(() -> viewBinding.recyclerView.post(() -> { + if(dataList.size() == resultLimit || pageSize == resultLimit) { + int page = (dataList.size() + resultLimit) / resultLimit; + loadMore(resultLimit, page); + } + })); - FragmentProfileFollowersFollowingBinding fragmentProfileFollowersFollowingBinding = FragmentProfileFollowersFollowingBinding.inflate(inflater, container, false); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL); + viewBinding.recyclerView.setHasFixedSize(true); + viewBinding.recyclerView.addItemDecoration(dividerItemDecoration); + viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + viewBinding.recyclerView.setAdapter(adapter); - TinyDB tinyDb = TinyDB.getInstance(getContext()); + loadInitial(resultLimit); - final SwipeRefreshLayout swipeRefresh = fragmentProfileFollowersFollowingBinding.pullToRefresh; + return viewBinding.getRoot(); + } - noDataFollowing = fragmentProfileFollowersFollowingBinding.noData; - mRecyclerView = fragmentProfileFollowersFollowingBinding.recyclerView; + private void loadInitial(int resultLimit) { - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL); + Call> call = RetrofitClient + .getApiInterface(context) + .getFollowing(Authorization.get(getContext()), 1, resultLimit); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.isSuccessful()) { + if(response.body() != null && response.body().size() > 0) { + dataList.clear(); + dataList.addAll(response.body()); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.GONE); + } + else { + dataList.clear(); + adapter.notifyDataChanged(); + viewBinding.noData.setVisibility(View.VISIBLE); + } + viewBinding.progressBar.setVisibility(View.GONE); + } + else if(response.code() == 404) { + viewBinding.noData.setVisibility(View.VISIBLE); + viewBinding.progressBar.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } + } - mRecyclerView.setHasFixedSize(true); - mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); - mRecyclerView.addItemDecoration(dividerItemDecoration); + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + } + }); + } - mProgressBar = fragmentProfileFollowersFollowingBinding.progressBar; + private void loadMore(int resultLimit, int page) { - swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + viewBinding.progressLoadMore.setVisibility(View.VISIBLE); + Call> call = RetrofitClient.getApiInterface(context) + .getFollowing(Authorization.get(getContext()), page, resultLimit); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.isSuccessful()) { + assert response.body() != null; + List result = response.body(); + if(result.size() > 0) { + pageSize = result.size(); + dataList.addAll(result); + } + else { + SnackBar.info(context, viewBinding.getRoot(), getString(R.string.noMoreData)); + adapter.setMoreDataAvailable(false); + } + adapter.notifyDataChanged(); + viewBinding.progressLoadMore.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } + } - swipeRefresh.setRefreshing(false); - ProfileFollowingViewModel.loadFollowingList(Authorization.get(getContext()), getContext()); - - }, 200)); - - fetchDataAsync(Authorization.get(getContext())); - - return fragmentProfileFollowersFollowingBinding.getRoot(); - } - - private void fetchDataAsync(String instanceToken) { - - ProfileFollowingViewModel pfModel = new ViewModelProvider(this).get(ProfileFollowingViewModel.class); - - pfModel.getFollowingList(instanceToken, getContext()).observe(getViewLifecycleOwner(), pfListMain -> { - - adapter = new MyProfileFollowingAdapter(getContext(), pfListMain); - - if(adapter.getItemCount() > 0) { - mRecyclerView.setAdapter(adapter); - noDataFollowing.setVisibility(View.GONE); - } - else { - adapter.notifyDataSetChanged(); - mRecyclerView.setAdapter(adapter); - noDataFollowing.setVisibility(View.VISIBLE); - } - - mProgressBar.setVisibility(View.GONE); - }); - - } - - public void onButtonPressed(Uri uri) { - if (mListener != null) { - mListener.onFragmentInteraction(uri); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - public interface OnFragmentInteractionListener { - void onFragmentInteraction(Uri uri); - } + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + } + }); + } } diff --git a/app/src/main/java/org/mian/gitnex/fragments/MyProfileFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFragment.java index 97e46874..85429cec 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/MyProfileFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyProfileFragment.java @@ -170,10 +170,10 @@ public class MyProfileFragment extends Fragment { switch (position) { case 0: // followers - return MyProfileFollowersFragment.newInstance("repoOwner", "repoName"); + return new MyProfileFollowersFragment(); case 1: // following - return MyProfileFollowingFragment.newInstance("repoOwner", "repoName"); + return new MyProfileFollowingFragment(); case 2: // emails return MyProfileEmailsFragment.newInstance("repoOwner", "repoName"); @@ -215,5 +215,4 @@ public class MyProfileFragment extends Fragment { return super.onOptionsItemSelected(item); } } - } diff --git a/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java index 0ae7c462..11d5ade6 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/NotificationsFragment.java @@ -4,6 +4,8 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -11,16 +13,12 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton; import org.apache.commons.lang3.StringUtils; import org.gitnex.tea4j.models.NotificationThread; import org.mian.gitnex.R; @@ -31,7 +29,7 @@ import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentNotificationsBinding; import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.Constants; -import org.mian.gitnex.helpers.InfiniteScrollListener; +import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; import java.io.IOException; @@ -44,28 +42,26 @@ import retrofit2.Response; /** * Author opyale + * Modified M M Arif */ public class NotificationsFragment extends Fragment implements NotificationsAdapter.OnNotificationClickedListener, NotificationsAdapter.OnMoreClickedListener, BottomSheetNotificationsFragment.OnOptionSelectedListener { + private FragmentNotificationsBinding viewBinding; private List notificationThreads; private NotificationsAdapter notificationsAdapter; private NotificationsActions notificationsActions; - private ExtendedFloatingActionButton markAllAsRead; - private ProgressBar progressBar; - private ProgressBar loadingMoreView; - private TextView noDataNotifications; - private SwipeRefreshLayout pullToRefresh; - private Activity activity; private Context context; private TinyDB tinyDB; private Menu menu; - private int pageCurrentIndex = 1; - private int pageResultLimit; + private int resultLimit; + private int pageSize; private String currentFilterMode = "unread"; + private final String TAG = Constants.tagNotifications; + private String instanceToken; @Override public void onCreate(@Nullable Bundle savedInstanceState) { @@ -77,194 +73,202 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - FragmentNotificationsBinding fragmentNotificationsBinding = FragmentNotificationsBinding.inflate(inflater, container, false); + viewBinding = FragmentNotificationsBinding.inflate(inflater, container, false); setHasOptionsMenu(true); activity = requireActivity(); context = getContext(); tinyDB = TinyDB.getInstance(context); - pageResultLimit = Constants.getCurrentResultLimit(context); - tinyDB.putString("notificationsFilterState", currentFilterMode); + String loginUid = tinyDB.getString("loginUid"); + instanceToken = "token " + tinyDB.getString(loginUid + "-token"); - markAllAsRead = fragmentNotificationsBinding.markAllAsRead; - noDataNotifications = fragmentNotificationsBinding.noDataNotifications; - loadingMoreView = fragmentNotificationsBinding.loadingMoreView; - progressBar = fragmentNotificationsBinding.progressBar; + resultLimit = Constants.getCurrentResultLimit(context); + tinyDB.putString("notificationsFilterState", currentFilterMode); notificationThreads = new ArrayList<>(); notificationsActions = new NotificationsActions(context); notificationsAdapter = new NotificationsAdapter(context, notificationThreads, this, this); - RecyclerView recyclerView = fragmentNotificationsBinding.notifications; LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context); - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(viewBinding.notifications.getContext(), DividerItemDecoration.VERTICAL); - recyclerView.setHasFixedSize(true); - recyclerView.setLayoutManager(linearLayoutManager); - recyclerView.setAdapter(notificationsAdapter); - recyclerView.addItemDecoration(dividerItemDecoration); - recyclerView.addOnScrollListener(new InfiniteScrollListener(pageResultLimit, linearLayoutManager) { + viewBinding.notifications.setHasFixedSize(true); + viewBinding.notifications.setLayoutManager(linearLayoutManager); + viewBinding.notifications.setAdapter(notificationsAdapter); + viewBinding.notifications.addItemDecoration(dividerItemDecoration); - @Override - public void onScrolledToEnd(int firstVisibleItemPosition) { - - pageCurrentIndex++; - loadNotifications(true); + viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + viewBinding.pullToRefresh.setRefreshing(false); + loadInitial(resultLimit); + notificationsAdapter.notifyDataChanged(); + }, 200)); + notificationsAdapter.setLoadMoreListener(() -> viewBinding.notifications.post(() -> { + if(notificationThreads.size() == resultLimit || pageSize == resultLimit) { + int page = (notificationThreads.size() + resultLimit) / resultLimit; + loadMore(resultLimit, page); } - }); + })); - recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + viewBinding.notifications.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - if(currentFilterMode.equalsIgnoreCase("unread")) { - - if(dy > 0 && markAllAsRead.isShown()) { - - markAllAsRead.setVisibility(View.GONE); - } else if(dy < 0) { - - markAllAsRead.setVisibility(View.VISIBLE); + if(dy > 0 && viewBinding.markAllAsRead.isShown()) { + viewBinding.markAllAsRead.setVisibility(View.GONE); + } + else if(dy < 0) { + viewBinding.markAllAsRead.setVisibility(View.VISIBLE); } } } @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - super.onScrollStateChanged(recyclerView, newState); } - }); - markAllAsRead.setOnClickListener(v1 -> { + viewBinding.markAllAsRead.setOnClickListener(v1 -> { Thread thread = new Thread(() -> { - try { - if(notificationsActions.setAllNotificationsRead(new Date())) { - activity.runOnUiThread(() -> { - Toasty.success(context, getString(R.string.markedNotificationsAsRead)); - loadNotifications(true); - + loadInitial(resultLimit); }); } } catch(IOException e) { - activity.runOnUiThread(() -> Toasty.error(context, getString(R.string.genericError))); Log.e("onError", e.toString()); - } }); - thread.start(); - }); - pullToRefresh = fragmentNotificationsBinding.pullToRefresh; - pullToRefresh.setOnRefreshListener(() -> { - - pageCurrentIndex = 1; - loadNotifications(false); - + viewBinding.pullToRefresh.setOnRefreshListener(() -> { + loadInitial(resultLimit); }); - loadNotifications(false); - return fragmentNotificationsBinding.getRoot(); - + loadInitial(resultLimit); + return viewBinding.getRoot(); } - private void loadNotifications(boolean append) { - - noDataNotifications.setVisibility(View.GONE); - - if(pageCurrentIndex == 1 || !append) { - - notificationThreads.clear(); - notificationsAdapter.notifyDataSetChanged(); - pullToRefresh.setRefreshing(false); - progressBar.setVisibility(View.VISIBLE); - - } else { - - loadingMoreView.setVisibility(View.VISIBLE); - } - - String loginUid = tinyDB.getString("loginUid"); - String instanceToken = "token " + tinyDB.getString(loginUid + "-token"); + private void loadInitial(int resultLimit) { + notificationThreads.clear(); + notificationsAdapter.notifyDataChanged(); + viewBinding.progressBar.setVisibility(View.VISIBLE); + notificationThreads.clear(); String[] filter = tinyDB.getString("notificationsFilterState").equals("read") ? new String[]{"pinned", "read"} : new String[]{"pinned", "unread"}; + viewBinding.pullToRefresh.setRefreshing(false); Call> call = RetrofitClient .getApiInterface(context) .getNotificationThreads(instanceToken, false, filter, Constants.defaultOldestTimestamp, "", - pageCurrentIndex, pageResultLimit); - + 1, resultLimit); call.enqueue(new Callback>() { - @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { - - if(response.code() == 200) { - - assert response.body() != null; - - if(!append) { - - notificationThreads.clear(); + if(response.isSuccessful()) { + if(response.body() != null && response.body().size() > 0) { + notificationThreads.addAll(response.body()); + notificationsAdapter.notifyDataChanged(); + viewBinding.noDataNotifications.setVisibility(View.GONE); } - - notificationThreads.addAll(response.body()); - notificationsAdapter.notifyDataSetChanged(); - - } else { - - Log.e("onError", String.valueOf(response.code())); + else { + notificationsAdapter.notifyDataChanged(); + viewBinding.noDataNotifications.setVisibility(View.VISIBLE); + } + viewBinding.progressBar.setVisibility(View.GONE); + } + else if(response.code() == 404) { + viewBinding.noDataNotifications.setVisibility(View.VISIBLE); + viewBinding.progressBar.setVisibility(View.GONE); + } + else { + notificationsAdapter.notifyDataChanged(); + Log.e(TAG, String.valueOf(response.code())); } - onCleanup(); - } @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - - Log.e("onError", t.toString()); + Log.e(TAG, t.toString()); onCleanup(); - - } - - private void onCleanup() { - - AppUtil.setMultiVisibility(View.GONE, loadingMoreView, progressBar); - pullToRefresh.setRefreshing(false); - - if(currentFilterMode.equalsIgnoreCase("unread")) { - - if(notificationThreads.isEmpty()) { - - noDataNotifications.setVisibility(View.VISIBLE); - markAllAsRead.setVisibility(View.GONE); - } - else { - markAllAsRead.setVisibility(View.VISIBLE); - } - } } }); } + private void loadMore(int resultLimit, int page) { + + String[] filter = tinyDB.getString("notificationsFilterState").equals("read") ? + new String[]{"pinned", "read"} : + new String[]{"pinned", "unread"}; + + viewBinding.loadingMoreView.setVisibility(View.VISIBLE); + Call> call = RetrofitClient.getApiInterface(context) + .getNotificationThreads(instanceToken, false, filter, + Constants.defaultOldestTimestamp, "", + page, resultLimit); + call.enqueue(new Callback>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + if(response.code() == 200) { + assert response.body() != null; + List result = response.body(); + + if(result.size() > 0) { + pageSize = result.size(); + notificationThreads.addAll(result); + } + else { + SnackBar.info(context, viewBinding.getRoot(), getString(R.string.noMoreData)); + notificationsAdapter.setMoreDataAvailable(false); + } + notificationsAdapter.notifyDataChanged(); + viewBinding.loadingMoreView.setVisibility(View.GONE); + } + else { + Log.e(TAG, String.valueOf(response.code())); + } + onCleanup(); + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e(TAG, t.toString()); + onCleanup(); + } + }); + } + + private void onCleanup() { + + AppUtil.setMultiVisibility(View.GONE, viewBinding.loadingMoreView, viewBinding.progressBar); + viewBinding.pullToRefresh.setRefreshing(false); + + if(currentFilterMode.equalsIgnoreCase("unread")) { + + if(notificationThreads.isEmpty()) { + viewBinding.noDataNotifications.setVisibility(View.VISIBLE); + viewBinding.markAllAsRead.setVisibility(View.GONE); + } + else { + viewBinding.markAllAsRead.setVisibility(View.VISIBLE); + } + } + } + private void changeFilterMode() { int filterIcon = currentFilterMode.equalsIgnoreCase("read") ? @@ -274,11 +278,10 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap menu.getItem(0).setIcon(filterIcon); if(currentFilterMode.equalsIgnoreCase("read")) { - - markAllAsRead.setVisibility(View.GONE); - } else { - - markAllAsRead.setVisibility(View.VISIBLE); + viewBinding.markAllAsRead.setVisibility(View.GONE); + } + else { + viewBinding.markAllAsRead.setVisibility(View.VISIBLE); } } @@ -286,14 +289,11 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { this.menu = menu; - inflater.inflate(R.menu.filter_menu_notifications, menu); - currentFilterMode = tinyDB.getString("notificationsFilterState"); changeFilterMode(); super.onCreateOptionsMenu(menu, inflater); - } @Override @@ -305,37 +305,25 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap bottomSheetNotificationsFilterFragment.show(getChildFragmentManager(), "notificationsFilterBottomSheet"); bottomSheetNotificationsFilterFragment.setOnDismissedListener(() -> { - pageCurrentIndex = 1; currentFilterMode = tinyDB.getString("notificationsFilterState"); - changeFilterMode(); - loadNotifications(false); - + loadInitial(resultLimit); }); - return true; - } - return super.onOptionsItemSelected(item); - } @Override public void onNotificationClicked(NotificationThread notificationThread) { Thread thread = new Thread(() -> { - try { - if(notificationThread.isUnread()) { - notificationsActions.setNotificationStatus(notificationThread, NotificationsActions.NotificationStatus.READ); - activity.runOnUiThread(() -> loadNotifications(false)); - + activity.runOnUiThread(() -> loadInitial(resultLimit)); } } catch(IOException ignored) {} - }); thread.start(); @@ -344,31 +332,23 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap Intent intent = new Intent(context, IssueDetailActivity.class); String issueUrl = notificationThread.getSubject().getUrl(); - tinyDB.putString("issueNumber", issueUrl.substring(issueUrl.lastIndexOf("/") + 1)); tinyDB.putString("issueType", notificationThread.getSubject().getType()); tinyDB.putString("repoFullName", notificationThread.getRepository().getFullName()); startActivity(intent); - } } @Override public void onMoreClicked(NotificationThread notificationThread) { - BottomSheetNotificationsFragment bottomSheetNotificationsFragment = new BottomSheetNotificationsFragment(); bottomSheetNotificationsFragment.onAttach(context, notificationThread, this); bottomSheetNotificationsFragment.show(getChildFragmentManager(), "notificationsBottomSheet"); - } @Override public void onSelected() { - - pageCurrentIndex = 1; - loadNotifications(false); - + loadInitial(resultLimit); } - } diff --git a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java index e9ce2c34..af6ce998 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java @@ -18,7 +18,6 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -import org.gitnex.tea4j.models.IssueComments; import org.gitnex.tea4j.models.Releases; import org.mian.gitnex.adapters.ReleasesAdapter; import org.mian.gitnex.databinding.FragmentReleasesBinding; diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java index 8c389444..5dff151b 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/DetailFragment.java @@ -149,6 +149,7 @@ public class DetailFragment extends Fragment { break; } } + binding.progressBar.setVisibility(View.GONE); } @Override diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java index d4ebef5a..fa77db3a 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowersFragment.java @@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.SnackBar; -import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; -import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; import retrofit2.Call; @@ -47,7 +45,7 @@ public class FollowersFragment extends Fragment { private FollowersAdapter adapter; private int pageSize; - private int resultLimit = Constants.resultLimitOldGiteaInstances; + private int resultLimit; private static final String usernameBundle = ""; private String username; @@ -78,13 +76,7 @@ public class FollowersFragment extends Fragment { setHasOptionsMenu(true); context = getContext(); - TinyDB tinyDb = TinyDB.getInstance(context); - - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - resultLimit = Constants.resultLimitNewGiteaInstances; - } - + resultLimit = Constants.getCurrentResultLimit(context); usersList = new ArrayList<>(); fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java index 82390c85..dd101818 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/FollowingFragment.java @@ -18,7 +18,6 @@ import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import org.gitnex.tea4j.models.UserInfo; import org.mian.gitnex.R; -import org.mian.gitnex.adapters.profile.FollowersAdapter; import org.mian.gitnex.adapters.profile.FollowingAdapter; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; @@ -26,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.SnackBar; -import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; -import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; import retrofit2.Call; @@ -48,7 +45,7 @@ public class FollowingFragment extends Fragment { private FollowingAdapter adapter; private int pageSize; - private int resultLimit = Constants.resultLimitOldGiteaInstances; + private int resultLimit; private static final String usernameBundle = ""; private String username; @@ -79,13 +76,7 @@ public class FollowingFragment extends Fragment { setHasOptionsMenu(true); context = getContext(); - TinyDB tinyDb = TinyDB.getInstance(context); - - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - resultLimit = Constants.resultLimitNewGiteaInstances; - } - + resultLimit = Constants.getCurrentResultLimit(context); usersList = new ArrayList<>(); fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java index 1f5268e6..61bfae59 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/OrganizationsFragment.java @@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.SnackBar; -import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; -import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; import retrofit2.Call; @@ -47,7 +45,7 @@ public class OrganizationsFragment extends Fragment { private OrganizationsAdapter adapter; private int pageSize; - private int resultLimit = Constants.resultLimitOldGiteaInstances; + private int resultLimit; private static final String usernameBundle = ""; private String username; @@ -78,13 +76,7 @@ public class OrganizationsFragment extends Fragment { setHasOptionsMenu(true); context = getContext(); - TinyDB tinyDb = TinyDB.getInstance(context); - - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - resultLimit = Constants.resultLimitNewGiteaInstances; - } - + resultLimit = Constants.getCurrentResultLimit(context); organizationsList = new ArrayList<>(); fragmentOrganizationsBinding.addNewOrganization.setVisibility(View.GONE); diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java index 74d84d3a..a2a96777 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/RepositoriesFragment.java @@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.SnackBar; -import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; -import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; import retrofit2.Call; @@ -47,7 +45,7 @@ public class RepositoriesFragment extends Fragment { private RepositoriesAdapter adapter; private int pageSize; - private int resultLimit = Constants.resultLimitOldGiteaInstances; + private int resultLimit; private static final String usernameBundle = ""; private String username; @@ -78,13 +76,7 @@ public class RepositoriesFragment extends Fragment { setHasOptionsMenu(true); context = getContext(); - TinyDB tinyDb = TinyDB.getInstance(context); - - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - resultLimit = Constants.resultLimitNewGiteaInstances; - } - + resultLimit = Constants.getCurrentResultLimit(context); reposList = new ArrayList<>(); fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE); diff --git a/app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java index 38f7180d..ae97c37f 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/profile/StarredRepositoriesFragment.java @@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.SnackBar; -import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Toasty; -import org.mian.gitnex.helpers.Version; import java.util.ArrayList; import java.util.List; import retrofit2.Call; @@ -47,7 +45,7 @@ public class StarredRepositoriesFragment extends Fragment { private StarredRepositoriesAdapter adapter; private int pageSize; - private int resultLimit = Constants.resultLimitOldGiteaInstances; + private int resultLimit; private static final String usernameBundle = ""; private String username; @@ -77,13 +75,8 @@ public class StarredRepositoriesFragment extends Fragment { fragmentRepositoriesBinding = org.mian.gitnex.databinding.FragmentRepositoriesBinding.inflate(inflater, container, false); setHasOptionsMenu(true); context = getContext(); - TinyDB tinyDb = TinyDB.getInstance(context); - - // if gitea is 1.12 or higher use the new limit - if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { - resultLimit = Constants.resultLimitNewGiteaInstances; - } + resultLimit = Constants.getCurrentResultLimit(context); reposList = new ArrayList<>(); fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE); diff --git a/app/src/main/java/org/mian/gitnex/helpers/Constants.java b/app/src/main/java/org/mian/gitnex/helpers/Constants.java index 65519048..8c8dca85 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/Constants.java +++ b/app/src/main/java/org/mian/gitnex/helpers/Constants.java @@ -14,10 +14,8 @@ public class Constants { public static final String defaultOldestTimestamp = "1970-01-01T00:00:00+00:00"; public static int getCurrentResultLimit(Context context) { - Version version = new Version(TinyDB.getInstance(context).getString("giteaVersion")); return version.higherOrEqual("1.12") ? resultLimitNewGiteaInstances : resultLimitOldGiteaInstances; - } // tags @@ -30,6 +28,11 @@ public class Constants { public static final String tagDraftsBottomSheet = "BottomSheetDraftsFragment"; public static final String userAccountsApi = "UserAccountsApi"; public static final String publicOrganizations = "PublicOrganizations"; + public static final String exploreIssues = "ExploreIssues"; + public static final String exploreRepositories = "ExploreRepositories"; + public static final String tagNotifications = "TagNotifications"; + public static final String tagFollowers = "TagFollowers"; + public static final String tagFollowing = "TagFollowing"; // issues variables public static final int issuesPageInit = 1; diff --git a/app/src/main/java/org/mian/gitnex/helpers/InfiniteScrollListener.java b/app/src/main/java/org/mian/gitnex/helpers/InfiniteScrollListener.java deleted file mode 100644 index 99005295..00000000 --- a/app/src/main/java/org/mian/gitnex/helpers/InfiniteScrollListener.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2016 Piotr Wittchen - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mian.gitnex.helpers; - -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -/** - * InfiniteScrollListener, which can be added to RecyclerView with addOnScrollListener - * to detect moment when RecyclerView was scrolled to the end. - */ -public abstract class InfiniteScrollListener extends RecyclerView.OnScrollListener { - private final int maxItemsPerRequest; - private final LinearLayoutManager layoutManager; - - /** - * Initializes InfiniteScrollListener, which can be added - * to RecyclerView with addOnScrollListener method - * - * @param maxItemsPerRequest Max items to be loaded in a single request. - * @param layoutManager LinearLayoutManager created in the Activity. - */ - public InfiniteScrollListener(int maxItemsPerRequest, LinearLayoutManager layoutManager) { - assert maxItemsPerRequest > 0; - assert layoutManager != null; - - this.maxItemsPerRequest = maxItemsPerRequest; - this.layoutManager = layoutManager; - } - - /** - * Callback method to be invoked when the RecyclerView has been scrolled - * - * @param recyclerView The RecyclerView which scrolled. - * @param dx The amount of horizontal scroll. - * @param dy The amount of vertical scroll. - */ - @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { - super.onScrolled(recyclerView, dx, dy); - if (canLoadMoreItems()) { - onScrolledToEnd(layoutManager.findFirstVisibleItemPosition()); - } - } - - /** - * Refreshes RecyclerView by setting new adapter, - * calling invalidate method and scrolling to given position - * - * @param view RecyclerView to be refreshed - * @param adapter adapter with new list of items to be loaded - * @param position position to which RecyclerView will be scrolled - */ - protected void refreshView(RecyclerView view, RecyclerView.Adapter adapter, int position) { - view.setAdapter(adapter); - view.invalidate(); - view.scrollToPosition(position); - } - - /** - * Checks if more items can be loaded to the RecyclerView - * - * @return boolean Returns true if can load more items or false if not. - */ - protected boolean canLoadMoreItems() { - final int visibleItemsCount = layoutManager.getChildCount(); - final int totalItemsCount = layoutManager.getItemCount(); - final int pastVisibleItemsCount = layoutManager.findFirstVisibleItemPosition(); - final boolean lastItemShown = visibleItemsCount + pastVisibleItemsCount >= totalItemsCount; - return lastItemShown && totalItemsCount >= maxItemsPerRequest; - } - - /** - * Callback method to be invoked when the RecyclerView has been scrolled to the end - * - * @param firstVisibleItemPosition Id of the first visible item on the list. - */ - public abstract void onScrolledToEnd(final int firstVisibleItemPosition); -} diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java deleted file mode 100644 index 6dc1be94..00000000 --- a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowersViewModel.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.mian.gitnex.viewmodels; - -import android.content.Context; -import android.util.Log; -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; -import org.gitnex.tea4j.models.UserInfo; -import org.mian.gitnex.clients.RetrofitClient; -import java.util.List; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -/** - * Author M M Arif - */ - -public class ProfileFollowersViewModel extends ViewModel { - - private static MutableLiveData> followersList; - - public LiveData> getFollowersList(String token, Context ctx) { - - followersList = new MutableLiveData<>(); - loadFollowersList(token, ctx); - - return followersList; - } - - public static void loadFollowersList(String token, Context ctx) { - - Call> call = RetrofitClient - .getApiInterface(ctx) - .getFollowers(token, 1, 50); - - call.enqueue(new Callback>() { - - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - - if (response.isSuccessful()) { - followersList.postValue(response.body()); - } else { - Log.i("onResponse", String.valueOf(response.code())); - } - - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.i("onFailure", t.toString()); - } - - }); - } - -} diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java deleted file mode 100644 index 871d0a3a..00000000 --- a/app/src/main/java/org/mian/gitnex/viewmodels/ProfileFollowingViewModel.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.mian.gitnex.viewmodels; - -import android.content.Context; -import android.util.Log; -import androidx.annotation.NonNull; -import androidx.lifecycle.LiveData; -import androidx.lifecycle.MutableLiveData; -import androidx.lifecycle.ViewModel; -import org.gitnex.tea4j.models.UserInfo; -import org.mian.gitnex.clients.RetrofitClient; -import java.util.List; -import retrofit2.Call; -import retrofit2.Callback; -import retrofit2.Response; - -/** - * Author M M Arif - */ - -public class ProfileFollowingViewModel extends ViewModel { - - private static MutableLiveData> followingList; - - public LiveData> getFollowingList(String token, Context ctx) { - - followingList = new MutableLiveData<>(); - loadFollowingList(token, ctx); - - return followingList; - } - - public static void loadFollowingList(String token, Context ctx) { - - Call> call = RetrofitClient - .getApiInterface(ctx) - .getFollowing(token, 1, 50); - - call.enqueue(new Callback>() { - - @Override - public void onResponse(@NonNull Call> call, @NonNull Response> response) { - - if (response.isSuccessful()) { - followingList.postValue(response.body()); - } else { - Log.i("onResponse", String.valueOf(response.code())); - } - - } - - @Override - public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.i("onFailure", t.toString()); - } - - }); - } - -} diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml index ece7ae9b..e746a7ad 100644 --- a/app/src/main/res/layout/fragment_notifications.xml +++ b/app/src/main/res/layout/fragment_notifications.xml @@ -16,7 +16,9 @@ + android:layout_height="match_parent" + android:background="?attr/primaryBackgroundColor" + android:scrollbars="vertical" /> diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index ea65f0b3..40c5b5a8 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -1,103 +1,100 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/app/src/main/res/layout/fragment_profile_detail.xml b/app/src/main/res/layout/fragment_profile_detail.xml index a592e763..d87486bf 100644 --- a/app/src/main/res/layout/fragment_profile_detail.xml +++ b/app/src/main/res/layout/fragment_profile_detail.xml @@ -13,6 +13,14 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> + +