Refactors and clean up (#979)

Related #278

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/979
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
This commit is contained in:
M M Arif 2021-09-29 11:29:39 +02:00
parent b493dfc567
commit f4cd3c9a4d
26 changed files with 1214 additions and 1220 deletions

View File

@ -1,5 +1,6 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -34,31 +35,69 @@ import java.util.Locale;
* Author M M Arif * Author M M Arif
*/ */
public class ExploreIssuesAdapter extends RecyclerView.Adapter<ExploreIssuesAdapter.SearchViewHolder> { public class ExploreIssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<Issues> searchedList;
private final Context context; private final Context context;
private final int TYPE_LOAD = 0;
private List<Issues> searchedList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final TinyDB tinyDb; private final TinyDB tinyDb;
public ExploreIssuesAdapter(List<Issues> dataList, Context ctx) { public ExploreIssuesAdapter(List<Issues> dataList, Context ctx) {
this.context = ctx; this.context = ctx;
this.searchedList = dataList; this.searchedList = dataList;
this.tinyDb = TinyDB.getInstance(context); 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 Issues issue;
private final ImageView issueAssigneeAvatar; private final ImageView issueAssigneeAvatar;
private final TextView issueTitle; private final TextView issueTitle;
private final TextView issueCreatedTime; private final TextView issueCreatedTime;
private final TextView issueCommentsCount; private final TextView issueCommentsCount;
private SearchViewHolder(View itemView) { IssuesHolder(View itemView) {
super(itemView); super(itemView);
issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar); issueAssigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
issueTitle = itemView.findViewById(R.id.issueTitle); issueTitle = itemView.findViewById(R.id.issueTitle);
issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount); issueCommentsCount = itemView.findViewById(R.id.issueCommentsCount);
@ -108,68 +147,79 @@ public class ExploreIssuesAdapter extends RecyclerView.Adapter<ExploreIssuesAdap
return true; return true;
}); });
} }
}
@NonNull @SuppressLint("SetTextI18n")
@Override void bindData(Issues issue) {
public ExploreIssuesAdapter.SearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { this.issue = issue;
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_issues, parent, false); Locale locale = context.getResources().getConfiguration().locale;
return new ExploreIssuesAdapter.SearchViewHolder(v); String timeFormat = tinyDb.getString("dateFormat");
}
@Override PicassoService.getInstance(context).get()
public void onBindViewHolder(@NonNull final ExploreIssuesAdapter.SearchViewHolder holder, int position) { .load(issue.getUser().getAvatar_url())
.placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(imgRadius, 0))
.resize(120, 120)
.centerCrop()
.into(issueAssigneeAvatar);
Issues currentItem = searchedList.get(position); String issueNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + issue.getRepository().getFull_name() + context.getResources().getString(R.string.hash) + issue.getNumber() + "</font>";
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
Locale locale = context.getResources().getConfiguration().locale; issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + issue.getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY));
String timeFormat = tinyDb.getString("dateFormat"); issueCommentsCount.setText(String.valueOf(issue.getComments()));
PicassoService.getInstance(context).get() switch(timeFormat) {
.load(currentItem.getUser().getAvatar_url()) case "pretty": {
.placeholder(R.drawable.loader_animated) PrettyTime prettyTime = new PrettyTime(locale);
.transform(new RoundedTransformation(imgRadius, 0)) String createdTime = prettyTime.format(issue.getCreated_at());
.resize(120, 120) issueCreatedTime.setText(createdTime);
.centerCrop() issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issue.getCreated_at()), context));
.into(holder.issueAssigneeAvatar); break;
}
String issueNumber_ = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + currentItem.getRepository().getFull_name() + context.getResources().getString(R.string.hash) + currentItem.getNumber() + "</font>"; case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
holder.issue = currentItem; String createdTime = formatter.format(issue.getCreated_at());
holder.issueTitle.setText(HtmlCompat.fromHtml(issueNumber_ + " " + currentItem.getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY)); issueCreatedTime.setText(createdTime);
holder.issueCommentsCount.setText(String.valueOf(currentItem.getComments())); break;
}
switch(timeFormat) { case "normal1": {
case "pretty": { DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
PrettyTime prettyTime = new PrettyTime(locale); String createdTime = formatter.format(issue.getCreated_at());
String createdTime = prettyTime.format(currentItem.getCreated_at()); issueCreatedTime.setText(createdTime);
holder.issueCreatedTime.setText(createdTime); break;
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;
} }
} }
} }
@Override static class LoadHolder extends RecyclerView.ViewHolder {
public int getItemCount() { LoadHolder(View itemView) {
return searchedList.size(); super(itemView);
}
} }
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() { public void notifyDataChanged() {
notifyDataSetChanged(); notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<Issues> list) {
searchedList = list;
notifyDataChanged();
} }
} }

View File

@ -1,5 +1,6 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
@ -40,19 +41,61 @@ import retrofit2.Callback;
* Author M M Arif * Author M M Arif
*/ */
public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepositoriesAdapter.ReposSearchViewHolder> { public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<UserRepositories> reposList;
private final Context context; private final Context context;
private final int TYPE_LOAD = 0;
private List<UserRepositories> reposList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final TinyDB tinyDb;
public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context ctx) { public ExploreRepositoriesAdapter(List<UserRepositories> dataList, Context ctx) {
this.context = ctx; this.context = ctx;
this.reposList = dataList; 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 UserRepositories userRepositories;
private final ImageView image; private final ImageView image;
@ -63,8 +106,7 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
private final TextView repoStars; private final TextView repoStars;
private final TextView repoLastUpdated; private final TextView repoLastUpdated;
private ReposSearchViewHolder(View itemView) { RepositoriesHolder(View itemView) {
super(itemView); super(itemView);
repoName = itemView.findViewById(R.id.repoName); repoName = itemView.findViewById(R.id.repoName);
orgName = itemView.findViewById(R.id.orgName); orgName = itemView.findViewById(R.id.orgName);
@ -77,8 +119,6 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
itemView.setOnClickListener(v -> { itemView.setOnClickListener(v -> {
Context context = v.getContext(); Context context = v.getContext();
TinyDB tinyDb = TinyDB.getInstance(context);
Intent intent = new Intent(context, RepoDetailActivity.class); Intent intent = new Intent(context, RepoDetailActivity.class);
intent.putExtra("repoFullName", userRepositories.getFullName()); intent.putExtra("repoFullName", userRepositories.getFullName());
@ -153,98 +193,104 @@ public class ExploreRepositoriesAdapter extends RecyclerView.Adapter<ExploreRepo
}); });
} }
} @SuppressLint("SetTextI18n")
void bindData(UserRepositories userRepositories) {
this.userRepositories = userRepositories;
@NonNull int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
@Override Locale locale = context.getResources().getConfiguration().locale;
public ExploreRepositoriesAdapter.ReposSearchViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { String timeFormat = tinyDb.getString("dateFormat");
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_repositories, parent, false); orgName.setText(userRepositories.getFullName().split("/")[0]);
return new ExploreRepositoriesAdapter.ReposSearchViewHolder(v); repoName.setText(userRepositories.getFullName().split("/")[1]);
} repoStars.setText(userRepositories.getStars_count());
@Override ColorGenerator generator = ColorGenerator.MATERIAL;
public void onBindViewHolder(@NonNull final ExploreRepositoriesAdapter.ReposSearchViewHolder holder, int position) { int color = generator.getColor(userRepositories.getName());
String firstCharacter = String.valueOf(userRepositories.getFullName().charAt(0));
TinyDB tinyDb = TinyDB.getInstance(context); TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28).endConfig().buildRoundRect(firstCharacter, color, 3);
UserRepositories currentItem = reposList.get(position);
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
Locale locale = context.getResources().getConfiguration().locale; if(userRepositories.getAvatar_url() != null) {
String timeFormat = tinyDb.getString("dateFormat"); if(!userRepositories.getAvatar_url().equals("")) {
holder.userRepositories = currentItem; PicassoService.getInstance(context).get().load(userRepositories.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(image);
holder.orgName.setText(currentItem.getFullName().split("/")[0]); }
holder.repoName.setText(currentItem.getFullName().split("/")[1]); else {
holder.repoStars.setText(currentItem.getStars_count()); image.setImageDrawable(drawable);
}
ColorGenerator generator = ColorGenerator.MATERIAL;
int color = generator.getColor(currentItem.getName());
String firstCharacter = String.valueOf(currentItem.getFullName().charAt(0));
TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28).endConfig().buildRoundRect(firstCharacter, color, 3);
if(currentItem.getAvatar_url() != null) {
if(!currentItem.getAvatar_url().equals("")) {
PicassoService.getInstance(context).get().load(currentItem.getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(holder.image);
} }
else { else {
holder.image.setImageDrawable(drawable); image.setImageDrawable(drawable);
} }
}
else {
holder.image.setImageDrawable(drawable);
}
if(currentItem.getUpdated_at() != null) { if(userRepositories.getUpdated_at() != null) {
switch(timeFormat) { switch(timeFormat) {
case "pretty": { case "pretty": {
PrettyTime prettyTime = new PrettyTime(locale); PrettyTime prettyTime = new PrettyTime(locale);
String createdTime = prettyTime.format(currentItem.getUpdated_at()); String createdTime = prettyTime.format(userRepositories.getUpdated_at());
holder.repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime)); repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime));
holder.repoLastUpdated.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(currentItem.getUpdated_at()), context)); repoLastUpdated.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(userRepositories.getUpdated_at()), context));
break; break;
} }
case "normal": { case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(currentItem.getUpdated_at()); String createdTime = formatter.format(userRepositories.getUpdated_at());
holder.repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime)); repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime));
break; break;
} }
case "normal1": { case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale); DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", locale);
String createdTime = formatter.format(currentItem.getUpdated_at()); String createdTime = formatter.format(userRepositories.getUpdated_at());
holder.repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime)); repoLastUpdated.setText(context.getString(R.string.lastUpdatedAt, createdTime));
break; break;
}
} }
} }
} else {
else { repoLastUpdated.setVisibility(View.GONE);
holder.repoLastUpdated.setVisibility(View.GONE); }
}
if(!currentItem.getDescription().equals("")) { if(!userRepositories.getDescription().equals("")) {
holder.repoDescription.setText(currentItem.getDescription()); repoDescription.setText(userRepositories.getDescription());
} }
else { else {
holder.repoDescription.setText(context.getString(R.string.noDataDescription)); repoDescription.setText(context.getString(R.string.noDataDescription));
} }
if(holder.isRepoAdmin == null) { if(isRepoAdmin == null) {
holder.isRepoAdmin = new CheckBox(context); isRepoAdmin = new CheckBox(context);
}
isRepoAdmin.setChecked(userRepositories.getPermissions().isAdmin());
} }
holder.isRepoAdmin.setChecked(currentItem.getPermissions().isAdmin());
} }
@Override static class LoadHolder extends RecyclerView.ViewHolder {
public int getItemCount() { LoadHolder(View itemView) {
super(itemView);
return reposList.size(); }
} }
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
}
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() { public void notifyDataChanged() {
notifyDataSetChanged(); notifyDataSetChanged();
isLoading = false;
} }
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<UserRepositories> list) {
reposList = list;
notifyDataChanged();
}
} }

View File

@ -1,5 +1,6 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.text.Html; import android.text.Html;
@ -22,79 +23,129 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class MyProfileFollowersAdapter extends RecyclerView.Adapter<MyProfileFollowersAdapter.FollowersViewHolder> { public class MyProfileFollowersAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<UserInfo> followersList; private final Context context;
private final Context context; private final int TYPE_LOAD = 0;
private List<UserInfo> followersList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
class FollowersViewHolder extends RecyclerView.ViewHolder { public MyProfileFollowersAdapter(List<UserInfo> 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; @Override
private final TextView userFullName; public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
private final TextView userName; 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); @Override
userFullName = itemView.findViewById(R.id.userFullName); public int getItemCount() {
userName = itemView.findViewById(R.id.userName); return followersList.size();
}
itemView.setOnClickListener(loginId -> { class FollowersHolder extends RecyclerView.ViewHolder {
Intent intent = new Intent(context, ProfileActivity.class); private UserInfo userInfo;
intent.putExtra("username", userLoginId); private final ImageView userAvatar;
context.startActivity(intent); private final TextView userFullName;
}); private final TextView userName;
itemView.setOnLongClickListener(loginId -> { FollowersHolder(View itemView) {
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); super(itemView);
return true;
});
}
}
public MyProfileFollowersAdapter(Context ctx, List<UserInfo> followersListMain) { userAvatar = itemView.findViewById(R.id.userAvatar);
userFullName = itemView.findViewById(R.id.userFullName);
userName = itemView.findViewById(R.id.userName);
this.context = ctx; itemView.setOnClickListener(loginId -> {
this.followersList = followersListMain; Intent intent = new Intent(context, ProfileActivity.class);
} intent.putExtra("username", userInfo.getLogin());
context.startActivity(intent);
});
@NonNull itemView.setOnLongClickListener(loginId -> {
@Override AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin()));
public MyProfileFollowersAdapter.FollowersViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return true;
});
}
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_followers_following, parent, false); @SuppressLint("SetTextI18n")
return new FollowersViewHolder(v); void bindData(UserInfo userInfo) {
} this.userInfo = userInfo;
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
@Override if(!userInfo.getFullname().equals("")) {
public void onBindViewHolder(@NonNull MyProfileFollowersAdapter.FollowersViewHolder holder, int position) { 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); PicassoService.getInstance(context).get().load(userInfo.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(userAvatar);
int imgRadius = AppUtil.getPixelsFromDensity(context, 3); }
}
holder.userLoginId = currentItem.getLogin(); static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
if(!currentItem.getFullname().equals("")) { public void setMoreDataAvailable(boolean moreDataAvailable) {
holder.userFullName.setText(Html.fromHtml(currentItem.getFullname())); isMoreDataAvailable = moreDataAvailable;
holder.userName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername())); }
}
else {
holder.userFullName.setText(currentItem.getUsername());
holder.userName.setVisibility(View.GONE);
}
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 interface OnLoadMoreListener {
public int getItemCount() { void onLoadMore();
return followersList.size(); }
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<UserInfo> list) {
followersList = list;
notifyDataChanged();
}
} }

View File

@ -1,5 +1,6 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.text.Html; import android.text.Html;
@ -22,78 +23,127 @@ import java.util.List;
* Author M M Arif * Author M M Arif
*/ */
public class MyProfileFollowingAdapter extends RecyclerView.Adapter<MyProfileFollowingAdapter.FollowingViewHolder> { public class MyProfileFollowingAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<UserInfo> followingList; private final Context context;
private final Context context; private final int TYPE_LOAD = 0;
private List<UserInfo> followingList;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
class FollowingViewHolder extends RecyclerView.ViewHolder { public MyProfileFollowingAdapter(List<UserInfo> 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; @Override
private final TextView userFullName; public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
private final TextView userName; 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); @Override
userFullName = itemView.findViewById(R.id.userFullName); public int getItemCount() {
userName = itemView.findViewById(R.id.userName); return followingList.size();
}
itemView.setOnClickListener(loginId -> { class FollowingHolder extends RecyclerView.ViewHolder {
Intent intent = new Intent(context, ProfileActivity.class); private UserInfo userInfo;
intent.putExtra("username", userLoginId); private final ImageView userAvatar;
context.startActivity(intent); private final TextView userFullName;
}); private final TextView userName;
itemView.setOnLongClickListener(loginId -> { FollowingHolder(View itemView) {
AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); super(itemView);
return true;
});
}
}
public MyProfileFollowingAdapter(Context ctx, List<UserInfo> followingListMain) { userAvatar = itemView.findViewById(R.id.userAvatar);
userFullName = itemView.findViewById(R.id.userFullName);
userName = itemView.findViewById(R.id.userName);
this.context = ctx; itemView.setOnClickListener(loginId -> {
this.followingList = followingListMain; Intent intent = new Intent(context, ProfileActivity.class);
} intent.putExtra("username", userInfo.getLogin());
context.startActivity(intent);
});
@NonNull itemView.setOnLongClickListener(loginId -> {
@Override AppUtil.copyToClipboard(context, userInfo.getLogin(), context.getString(R.string.copyLoginIdToClipBoard, userInfo.getLogin()));
public MyProfileFollowingAdapter.FollowingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return true;
});
}
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_profile_followers_following, parent, false); @SuppressLint("SetTextI18n")
return new FollowingViewHolder(v); void bindData(UserInfo userInfo) {
} this.userInfo = userInfo;
int imgRadius = AppUtil.getPixelsFromDensity(context, 3);
@Override if(!userInfo.getFullname().equals("")) {
public void onBindViewHolder(@NonNull MyProfileFollowingAdapter.FollowingViewHolder holder, int position) { 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); PicassoService.getInstance(context).get().load(userInfo.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(userAvatar);
int imgRadius = AppUtil.getPixelsFromDensity(context, 3); }
}
holder.userLoginId = currentItem.getLogin(); static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) {
super(itemView);
}
}
if(!currentItem.getFullname().equals("")) { public void setMoreDataAvailable(boolean moreDataAvailable) {
holder.userFullName.setText(Html.fromHtml(currentItem.getFullname())); isMoreDataAvailable = moreDataAvailable;
holder.userName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername())); }
}
else {
holder.userFullName.setText(currentItem.getUsername());
holder.userName.setVisibility(View.GONE);
}
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 interface OnLoadMoreListener {
public int getItemCount() { void onLoadMore();
return followingList.size(); }
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<UserInfo> list) {
followingList = list;
notifyDataChanged();
}
} }

View File

@ -1,5 +1,6 @@
package org.mian.gitnex.adapters; package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -21,18 +22,21 @@ import java.util.List;
/** /**
* Author opyale * Author opyale
* Modified M M Arif
*/ */
public class NotificationsAdapter extends RecyclerView.Adapter<NotificationsAdapter.NotificationsViewHolder> { public class NotificationsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final Context context; private final Context context;
private final List<NotificationThread> notificationThreads; private final int TYPE_LOAD = 0;
private List<NotificationThread> notificationThreads;
private final OnMoreClickedListener onMoreClickedListener; private final OnMoreClickedListener onMoreClickedListener;
private final OnNotificationClickedListener onNotificationClickedListener; private final OnNotificationClickedListener onNotificationClickedListener;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final TinyDB tinyDb; private final TinyDB tinyDb;
public NotificationsAdapter(Context context, List<NotificationThread> notificationThreads, OnMoreClickedListener onMoreClickedListener, OnNotificationClickedListener onNotificationClickedListener) { public NotificationsAdapter(Context context, List<NotificationThread> notificationThreads, OnMoreClickedListener onMoreClickedListener, OnNotificationClickedListener onNotificationClickedListener) {
this.tinyDb = TinyDB.getInstance(context); this.tinyDb = TinyDB.getInstance(context);
this.context = context; this.context = context;
this.notificationThreads = notificationThreads; this.notificationThreads = notificationThreads;
@ -40,7 +44,46 @@ public class NotificationsAdapter extends RecyclerView.Adapter<NotificationsAdap
this.onNotificationClickedListener = onNotificationClickedListener; this.onNotificationClickedListener = onNotificationClickedListener;
} }
static class NotificationsViewHolder 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 NotificationsAdapter.NotificationsHolder(inflater.inflate(R.layout.list_notifications, parent, false));
}
else {
return new NotificationsAdapter.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) {
((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 LinearLayout frame;
private final TextView subject; private final TextView subject;
@ -51,10 +94,9 @@ public class NotificationsAdapter extends RecyclerView.Adapter<NotificationsAdap
private final ImageView pinned; private final ImageView pinned;
private final ImageView more; private final ImageView more;
public NotificationsViewHolder(@NonNull View itemView) { NotificationsHolder(View itemView) {
super(itemView); super(itemView);
frame = itemView.findViewById(R.id.frame); frame = itemView.findViewById(R.id.frame);
subject = itemView.findViewById(R.id.subject); subject = itemView.findViewById(R.id.subject);
repository = itemView.findViewById(R.id.repository); repository = itemView.findViewById(R.id.repository);
@ -64,95 +106,102 @@ public class NotificationsAdapter extends RecyclerView.Adapter<NotificationsAdap
pinned = itemView.findViewById(R.id.pinned); pinned = itemView.findViewById(R.id.pinned);
more = itemView.findViewById(R.id.more); more = itemView.findViewById(R.id.more);
} }
}
@NonNull @SuppressLint("SetTextI18n")
@Override void bindData(NotificationThread notificationThread) {
public NotificationsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(context).inflate(R.layout.list_notifications, parent, false); String url = notificationThread.getSubject().getUrl();
return new NotificationsAdapter.NotificationsViewHolder(v); String subjectId = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources().getString(R.string.hash) + url.substring(url.lastIndexOf("/") + 1) + "</font>";
}
@Override subject.setText(HtmlCompat.fromHtml(subjectId + " " + notificationThread.getSubject().getTitle(), HtmlCompat.FROM_HTML_MODE_LEGACY));
public void onBindViewHolder(@NonNull NotificationsViewHolder holder, int position) { repository.setText(notificationThread.getRepository().getFullName());
NotificationThread notificationThread = notificationThreads.get(position); if(notificationThread.isPinned()) {
pinned.setVisibility(View.VISIBLE);
String url = notificationThread.getSubject().getUrl(); }
String subjectId = "<font color='" + ResourcesCompat.getColor(context.getResources(), R.color.lightGray, null) + "'>" + context.getResources() else {
.getString(R.string.hash) + url.substring(url.lastIndexOf("/") + 1) + "</font>"; pinned.setVisibility(View.GONE);
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());
} }
});
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 static class LoadHolder extends RecyclerView.ViewHolder {
public int getItemCount() { 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<NotificationThread> list) {
notificationThreads = list;
notifyDataChanged();
} }
public interface OnNotificationClickedListener { public interface OnNotificationClickedListener {
void onNotificationClicked(NotificationThread notificationThread); void onNotificationClicked(NotificationThread notificationThread);
} }
public interface OnMoreClickedListener { public interface OnMoreClickedListener {
void onMoreClicked(NotificationThread notificationThread); void onMoreClicked(NotificationThread notificationThread);
} }
} }

View File

@ -2,6 +2,8 @@ package org.mian.gitnex.fragments;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -13,12 +15,13 @@ import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import org.gitnex.tea4j.models.Issues; import org.gitnex.tea4j.models.Issues;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.ExploreIssuesAdapter; import org.mian.gitnex.adapters.ExploreIssuesAdapter;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentSearchIssuesBinding; import org.mian.gitnex.databinding.FragmentSearchIssuesBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -33,30 +36,22 @@ import retrofit2.Response;
public class ExploreIssuesFragment extends Fragment { public class ExploreIssuesFragment extends Fragment {
private FragmentSearchIssuesBinding viewBinding; private FragmentSearchIssuesBinding viewBinding;
private ExploreIssuesAdapter adapter; private Context context;
private List<Issues> dataList;
Context ctx;
private int apiCallCurrentValue = 10; private List<Issues> dataList;
private int pageCurrentIndex = 1; 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 @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
viewBinding = FragmentSearchIssuesBinding.inflate(inflater, container, false); viewBinding = FragmentSearchIssuesBinding.inflate(inflater, container, false);
setHasOptionsMenu(true); context = getContext();
ctx = getContext();
dataList = new ArrayList<>(); dataList = new ArrayList<>();
adapter = new ExploreIssuesAdapter(dataList, ctx); adapter = new ExploreIssuesAdapter(dataList, context);
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);
viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> { viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> {
if(actionId == EditorInfo.IME_ACTION_SEND) { if(actionId == EditorInfo.IME_ACTION_SEND) {
@ -64,87 +59,111 @@ public class ExploreIssuesFragment extends Fragment {
InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(viewBinding.searchKeyword.getWindowToken(), 0); imm.hideSoftInputFromWindow(viewBinding.searchKeyword.getWindowToken(), 0);
pageCurrentIndex = 1;
apiCallCurrentValue = 10;
viewBinding.progressBar.setVisibility(View.VISIBLE); 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; return false;
}); });
viewBinding.recyclerViewSearchIssues.addOnScrollListener(new InfiniteScrollListener(pageCurrentIndex, linearLayoutManager) { viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
@Override viewBinding.pullToRefresh.setRefreshing(false);
public void onScrolledToEnd(int firstVisibleItemPosition) { loadInitial("", resultLimit);
pageCurrentIndex++; adapter.notifyDataChanged();
loadData(true, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString()); }, 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(() -> { DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL);
pageCurrentIndex = 1; viewBinding.recyclerViewSearchIssues.setHasFixedSize(true);
apiCallCurrentValue = 10; viewBinding.recyclerViewSearchIssues.addItemDecoration(dividerItemDecoration);
loadData(false, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString()); viewBinding.recyclerViewSearchIssues.setLayoutManager(new LinearLayoutManager(context));
}); viewBinding.recyclerViewSearchIssues.setAdapter(adapter);
loadData(false, ""); loadInitial("", resultLimit);
return viewBinding.getRoot(); return viewBinding.getRoot();
} }
private void loadData(boolean append, String searchKeyword) { private void loadInitial(String searchKeyword, int resultLimit) {
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<List<Issues>> call = RetrofitClient.getApiInterface(getContext())
.queryIssues(Authorization.get(getContext()), searchKeyword, "issues", "open", pageCurrentIndex);
Call<List<Issues>> call = RetrofitClient
.getApiInterface(context).queryIssues(Authorization.get(getContext()), searchKeyword, "issues", "open", resultLimit, 1);
call.enqueue(new Callback<List<Issues>>() { call.enqueue(new Callback<List<Issues>>() {
@Override @Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) { public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.code() == 200) { if(response.isSuccessful()) {
assert response.body() != null; if(response.body() != null && response.body().size() > 0) {
apiCallCurrentValue = response.body().size();
if(!append) {
dataList.clear(); dataList.clear();
dataList.addAll(response.body());
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.GONE);
} }
dataList.addAll(response.body()); else {
adapter.notifyDataSetChanged(); 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 { else {
dataList.clear(); Log.e(TAG, String.valueOf(response.code()));
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.VISIBLE);
} }
onCleanup();
} }
@Override @Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e("onFailure", Objects.requireNonNull(t.getMessage())); Log.e(TAG, t.toString());
onCleanup(); }
});
}
private void loadMore(String searchKeyword, int resultLimit, int page) {
viewBinding.loadingMoreView.setVisibility(View.VISIBLE);
Call<List<Issues>> call = RetrofitClient.getApiInterface(context)
.queryIssues(Authorization.get(getContext()), searchKeyword, "issues", "open", resultLimit, page);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
List<Issues> 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() { @Override
AppUtil.setMultiVisibility(View.GONE, viewBinding.loadingMoreView, viewBinding.progressBar); public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
if(dataList.isEmpty()) { Log.e(TAG, t.toString());
viewBinding.noData.setVisibility(View.VISIBLE);
}
} }
}); });
} }

View File

@ -22,7 +22,6 @@ import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import retrofit2.Call; import retrofit2.Call;
@ -41,7 +40,7 @@ public class ExplorePublicOrganizationsFragment extends Fragment {
private Context context; private Context context;
private int pageSize; private int pageSize;
private final String TAG = Constants.publicOrganizations; private final String TAG = Constants.publicOrganizations;
private int resultLimit = Constants.resultLimitOldGiteaInstances; private int resultLimit;
@Nullable @Nullable
@Override @Override
@ -54,10 +53,7 @@ public class ExplorePublicOrganizationsFragment extends Fragment {
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
// if gitea is 1.12 or higher use the new limit resultLimit = Constants.getCurrentResultLimit(context);
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = Constants.resultLimitNewGiteaInstances;
}
fragmentPublicOrgBinding.addNewOrganization.setVisibility(View.GONE); fragmentPublicOrgBinding.addNewOrganization.setVisibility(View.GONE);
organizationsList = new ArrayList<>(); organizationsList = new ArrayList<>();

View File

@ -6,6 +6,8 @@ import android.graphics.Color;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -26,12 +28,10 @@ import org.mian.gitnex.adapters.ExploreRepositoriesAdapter;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.CustomExploreRepositoriesDialogBinding; import org.mian.gitnex.databinding.CustomExploreRepositoriesDialogBinding;
import org.mian.gitnex.databinding.FragmentExploreRepoBinding; import org.mian.gitnex.databinding.FragmentExploreRepoBinding;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants; 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.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -42,19 +42,21 @@ import retrofit2.Response;
/** /**
* Template Author M M Arif * Template Author M M Arif
* Author 6543 * Author 6543
* Modified M M Arif
*/ */
public class ExploreRepositoriesFragment extends Fragment { public class ExploreRepositoriesFragment extends Fragment {
private FragmentExploreRepoBinding viewBinding; private FragmentExploreRepoBinding viewBinding;
private Context ctx; private Context context;
private TinyDB tinyDb; private TinyDB tinyDb;
private int pageCurrentIndex = 1; private int pageSize;
private boolean repoTypeInclude = true; private final boolean repoTypeInclude = true;
private String sort = "updated"; private final String sort = "updated";
private String order = "desc"; private final String order = "desc";
private int limit = 10; private final String TAG = Constants.exploreRepositories;
private int resultLimit;
private List<UserRepositories> dataList; private List<UserRepositories> dataList;
private ExploreRepositoriesAdapter adapter; private ExploreRepositoriesAdapter adapter;
@ -67,164 +69,130 @@ public class ExploreRepositoriesFragment extends Fragment {
viewBinding = FragmentExploreRepoBinding.inflate(inflater, container, false); viewBinding = FragmentExploreRepoBinding.inflate(inflater, container, false);
setHasOptionsMenu(true); setHasOptionsMenu(true);
ctx = getContext(); context = getContext();
tinyDb = TinyDB.getInstance(getContext()); tinyDb = TinyDB.getInstance(getContext());
dataList = new ArrayList<>(); dataList = new ArrayList<>();
adapter = new ExploreRepositoriesAdapter(dataList, ctx); adapter = new ExploreRepositoriesAdapter(dataList, context);
tinyDb.putBoolean("exploreRepoIncludeTopic", false); tinyDb.putBoolean("exploreRepoIncludeTopic", false);
tinyDb.putBoolean("exploreRepoIncludeDescription", false); tinyDb.putBoolean("exploreRepoIncludeDescription", false);
tinyDb.putBoolean("exploreRepoIncludeTemplate", false); tinyDb.putBoolean("exploreRepoIncludeTemplate", false);
tinyDb.putBoolean("exploreRepoOnlyArchived", false); tinyDb.putBoolean("exploreRepoOnlyArchived", false);
// if gitea is 1.12 or higher use the new limit resultLimit = Constants.getCurrentResultLimit(context);
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);
viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> { viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> {
if(actionId == EditorInfo.IME_ACTION_SEND) { if(actionId == EditorInfo.IME_ACTION_SEND) {
if(!Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString().equals("")) { if(!Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString().equals("")) {
InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(viewBinding.searchKeyword.getWindowToken(), 0); 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); 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; 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 adapter.setLoadMoreListener(() -> viewBinding.recyclerViewReposSearch.post(() -> {
public void onScrolledToEnd(int firstVisibleItemPosition) { if(dataList.size() == resultLimit || pageSize == resultLimit) {
int page = (dataList.size() + resultLimit) / resultLimit;
pageCurrentIndex++; loadMore(String.valueOf(viewBinding.searchKeyword.getText()), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"), resultLimit, page);
loadData(true, Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString(), tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"));
} }
}); }));
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; loadInitial("", tinyDb.getBoolean("exploreRepoIncludeTopic"), tinyDb.getBoolean("exploreRepoIncludeDescription"), tinyDb.getBoolean("exploreRepoIncludeTemplate"), tinyDb.getBoolean("exploreRepoOnlyArchived"), resultLimit);
// 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"));
return viewBinding.getRoot(); return viewBinding.getRoot();
} }
private void loadData(boolean append, String searchKeyword, boolean exploreRepoIncludeTopic, boolean exploreRepoIncludeDescription, boolean exploreRepoIncludeTemplate, boolean exploreRepoOnlyArchived) { private void loadInitial(String searchKeyword, boolean exploreRepoIncludeTopic, boolean exploreRepoIncludeDescription, boolean exploreRepoIncludeTemplate, boolean exploreRepoOnlyArchived, int resultLimit) {
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<ExploreRepositories> call = RetrofitClient.getApiInterface(ctx).queryRepos(Authorization.get(getContext()), searchKeyword, repoTypeInclude, sort, order, exploreRepoIncludeTopic, exploreRepoIncludeDescription, exploreRepoIncludeTemplate, exploreRepoOnlyArchived, limit, pageCurrentIndex);
Call<ExploreRepositories> call = RetrofitClient
.getApiInterface(context).queryRepos(Authorization.get(getContext()), searchKeyword, repoTypeInclude, sort, order, exploreRepoIncludeTopic, exploreRepoIncludeDescription, exploreRepoIncludeTemplate, exploreRepoOnlyArchived, resultLimit, 1);
call.enqueue(new Callback<ExploreRepositories>() { call.enqueue(new Callback<ExploreRepositories>() {
@Override @Override
public void onResponse(@NonNull Call<ExploreRepositories> call, @NonNull Response<ExploreRepositories> response) { public void onResponse(@NonNull Call<ExploreRepositories> call, @NonNull Response<ExploreRepositories> response) {
if(response.isSuccessful()) {
if(response.code() == 200) { if(response.body() != null && response.body().getSearchedData().size() > 0) {
assert response.body() != null;
limit = response.body().getSearchedData().size();
if(!append) {
dataList.clear(); dataList.clear();
dataList.addAll(response.body().getSearchedData());
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.GONE);
} }
else {
dataList.addAll(response.body().getSearchedData()); dataList.clear();
adapter.notifyDataSetChanged(); 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 { else {
Log.e(TAG, String.valueOf(response.code()));
dataList.clear();
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.VISIBLE);
} }
onCleanup();
} }
@Override @Override
public void onFailure(@NonNull Call<ExploreRepositories> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<ExploreRepositories> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
Log.e("onFailure", Objects.requireNonNull(t.getMessage())); private void loadMore(String searchKeyword, boolean exploreRepoIncludeTopic, boolean exploreRepoIncludeDescription, boolean exploreRepoIncludeTemplate, boolean exploreRepoOnlyArchived, int resultLimit, int page) {
onCleanup();
viewBinding.loadingMoreView.setVisibility(View.VISIBLE);
Call<ExploreRepositories> call = RetrofitClient.getApiInterface(context)
.queryRepos(Authorization.get(getContext()), searchKeyword, repoTypeInclude, sort, order, exploreRepoIncludeTopic, exploreRepoIncludeDescription, exploreRepoIncludeTemplate, exploreRepoOnlyArchived, resultLimit, page);
call.enqueue(new Callback<ExploreRepositories>() {
@Override
public void onResponse(@NonNull Call<ExploreRepositories> call, @NonNull Response<ExploreRepositories> response) {
if(response.isSuccessful()) {
assert response.body() != null;
List<UserRepositories> 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() { @Override
public void onFailure(@NonNull Call<ExploreRepositories> call, @NonNull Throwable t) {
AppUtil.setMultiVisibility(View.GONE, viewBinding.loadingMoreView, viewBinding.progressBar); Log.e(TAG, t.toString());
if(dataList.isEmpty()) {
viewBinding.noData.setVisibility(View.VISIBLE);
}
} }
}); });
} }
@ -235,7 +203,6 @@ public class ExploreRepositoriesFragment extends Fragment {
menu.clear(); menu.clear();
inflater.inflate(R.menu.filter_menu, menu); inflater.inflate(R.menu.filter_menu, menu);
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
MenuItem filter = menu.findItem(R.id.filter); MenuItem filter = menu.findItem(R.id.filter);
filter.setOnMenuItemClickListener(filter_ -> { filter.setOnMenuItemClickListener(filter_ -> {
@ -243,19 +210,17 @@ public class ExploreRepositoriesFragment extends Fragment {
showFilterOptions(); showFilterOptions();
return false; return false;
}); });
} }
private void showFilterOptions() { 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) { if (dialogFilterOptions.getWindow() != null) {
dialogFilterOptions.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); dialogFilterOptions.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
} }
filterBinding = CustomExploreRepositoriesDialogBinding.inflate(LayoutInflater.from(ctx)); filterBinding = CustomExploreRepositoriesDialogBinding.inflate(LayoutInflater.from(context));
View view = filterBinding.getRoot(); View view = filterBinding.getRoot();
dialogFilterOptions.setContentView(view); dialogFilterOptions.setContentView(view);
@ -290,13 +255,10 @@ public class ExploreRepositoriesFragment extends Fragment {
@Override @Override
public void onDetach() { public void onDetach() {
super.onDetach(); super.onDetach();
} }
public interface OnFragmentInteractionListener { public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri); void onFragmentInteraction(Uri uri);
} }
} }

View File

@ -1,25 +1,30 @@
package org.mian.gitnex.fragments; package org.mian.gitnex.fragments;
import android.net.Uri; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import org.gitnex.tea4j.models.UserInfo;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.mian.gitnex.R;
import org.mian.gitnex.adapters.MyProfileFollowersAdapter; import org.mian.gitnex.adapters.MyProfileFollowersAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding;
import org.mian.gitnex.helpers.Authorization; 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 * Author M M Arif
@ -27,106 +32,119 @@ import org.mian.gitnex.viewmodels.ProfileFollowersViewModel;
public class MyProfileFollowersFragment extends Fragment { public class MyProfileFollowersFragment extends Fragment {
private ProgressBar mProgressBar; private FragmentProfileFollowersFollowingBinding viewBinding;
private MyProfileFollowersAdapter adapter; private Context context;
private RecyclerView mRecyclerView;
private TextView noDataFollowers;
private static String repoNameF = "param2";
private static String repoOwnerF = "param1";
private String repoName; private List<UserInfo> dataList;
private String repoOwner; private MyProfileFollowersAdapter adapter;
private int pageSize;
private OnFragmentInteractionListener mListener; private final String TAG = Constants.tagFollowers;
private int resultLimit;
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);
}
}
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { 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; viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
mRecyclerView = fragmentProfileFollowersFollowingBinding.recyclerView; 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); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); viewBinding.recyclerView.setHasFixedSize(true);
mRecyclerView.addItemDecoration(dividerItemDecoration); 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(() -> { return viewBinding.getRoot();
swipeRefresh.setRefreshing(false);
ProfileFollowersViewModel.loadFollowersList(Authorization.get(getContext()), getContext());
}, 200));
fetchDataAsync(Authorization.get(getContext()));
return fragmentProfileFollowersFollowingBinding.getRoot();
} }
private void fetchDataAsync(String instanceToken) { private void loadInitial(int resultLimit) {
ProfileFollowersViewModel pfModel = new ViewModelProvider(this).get(ProfileFollowersViewModel.class); Call<List<UserInfo>> call = RetrofitClient
.getApiInterface(context)
.getFollowers(Authorization.get(getContext()), 1, resultLimit);
call.enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> 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<List<UserInfo>> 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) { viewBinding.progressLoadMore.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter); Call<List<UserInfo>> call = RetrofitClient.getApiInterface(context)
noDataFollowers.setVisibility(View.GONE); .getFollowers(Authorization.get(getContext()), page, resultLimit);
} call.enqueue(new Callback<List<UserInfo>>() {
else { @Override
adapter.notifyDataSetChanged(); public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> response) {
mRecyclerView.setAdapter(adapter); if(response.isSuccessful()) {
noDataFollowers.setVisibility(View.VISIBLE); assert response.body() != null;
} List<UserInfo> 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); @Override
}); public void onFailure(@NonNull Call<List<UserInfo>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
} }
});
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);
}
} }

View File

@ -1,26 +1,30 @@
package org.mian.gitnex.fragments; package org.mian.gitnex.fragments;
import android.net.Uri; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import org.gitnex.tea4j.models.UserInfo;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.mian.gitnex.R;
import org.mian.gitnex.adapters.MyProfileFollowingAdapter; import org.mian.gitnex.adapters.MyProfileFollowingAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.viewmodels.ProfileFollowingViewModel; 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 * Author M M Arif
@ -28,108 +32,118 @@ import org.mian.gitnex.viewmodels.ProfileFollowingViewModel;
public class MyProfileFollowingFragment extends Fragment { public class MyProfileFollowingFragment extends Fragment {
private ProgressBar mProgressBar; private FragmentProfileFollowersFollowingBinding viewBinding;
private MyProfileFollowingAdapter adapter; private Context context;
private RecyclerView mRecyclerView;
private TextView noDataFollowing;
private static final String repoNameF = "param2";
private static final String repoOwnerF = "param1";
private String repoName; private List<UserInfo> dataList;
private String repoOwner; 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) { dataList = new ArrayList<>();
MyProfileFollowingFragment fragment = new MyProfileFollowingFragment(); adapter = new MyProfileFollowingAdapter(dataList, context);
Bundle args = new Bundle(); resultLimit = Constants.getCurrentResultLimit(context);
args.putString(repoOwnerF, param1);
args.putString(repoNameF, param2);
fragment.setArguments(args);
return fragment;
}
@Override viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
public void onCreate(Bundle savedInstanceState) { viewBinding.pullToRefresh.setRefreshing(false);
super.onCreate(savedInstanceState); loadInitial(resultLimit);
if (getArguments() != null) { adapter.notifyDataChanged();
repoName = getArguments().getString(repoNameF); }, 200));
repoOwner = getArguments().getString(repoOwnerF);
}
}
@Override adapter.setLoadMoreListener(() -> viewBinding.recyclerView.post(() -> {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, if(dataList.size() == resultLimit || pageSize == resultLimit) {
Bundle savedInstanceState) { 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; private void loadInitial(int resultLimit) {
mRecyclerView = fragmentProfileFollowersFollowingBinding.recyclerView;
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL); Call<List<UserInfo>> call = RetrofitClient
.getApiInterface(context)
.getFollowing(Authorization.get(getContext()), 1, resultLimit);
call.enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> 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); @Override
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); public void onFailure(@NonNull Call<List<UserInfo>> call, @NonNull Throwable t) {
mRecyclerView.addItemDecoration(dividerItemDecoration); 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<List<UserInfo>> call = RetrofitClient.getApiInterface(context)
.getFollowing(Authorization.get(getContext()), page, resultLimit);
call.enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
List<UserInfo> 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); @Override
ProfileFollowingViewModel.loadFollowingList(Authorization.get(getContext()), getContext()); public void onFailure(@NonNull Call<List<UserInfo>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}, 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);
}
} }

View File

@ -170,10 +170,10 @@ public class MyProfileFragment extends Fragment {
switch (position) { switch (position) {
case 0: // followers case 0: // followers
return MyProfileFollowersFragment.newInstance("repoOwner", "repoName"); return new MyProfileFollowersFragment();
case 1: // following case 1: // following
return MyProfileFollowingFragment.newInstance("repoOwner", "repoName"); return new MyProfileFollowingFragment();
case 2: // emails case 2: // emails
return MyProfileEmailsFragment.newInstance("repoOwner", "repoName"); return MyProfileEmailsFragment.newInstance("repoOwner", "repoName");
@ -215,5 +215,4 @@ public class MyProfileFragment extends Fragment {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} }
} }

View File

@ -4,6 +4,8 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -11,16 +13,12 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; 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.apache.commons.lang3.StringUtils;
import org.gitnex.tea4j.models.NotificationThread; import org.gitnex.tea4j.models.NotificationThread;
import org.mian.gitnex.R; 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.databinding.FragmentNotificationsBinding;
import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.Constants; 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.TinyDB;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import java.io.IOException; import java.io.IOException;
@ -44,28 +42,26 @@ import retrofit2.Response;
/** /**
* Author opyale * Author opyale
* Modified M M Arif
*/ */
public class NotificationsFragment extends Fragment implements NotificationsAdapter.OnNotificationClickedListener, NotificationsAdapter.OnMoreClickedListener, BottomSheetNotificationsFragment.OnOptionSelectedListener { public class NotificationsFragment extends Fragment implements NotificationsAdapter.OnNotificationClickedListener, NotificationsAdapter.OnMoreClickedListener, BottomSheetNotificationsFragment.OnOptionSelectedListener {
private FragmentNotificationsBinding viewBinding;
private List<NotificationThread> notificationThreads; private List<NotificationThread> notificationThreads;
private NotificationsAdapter notificationsAdapter; private NotificationsAdapter notificationsAdapter;
private NotificationsActions notificationsActions; private NotificationsActions notificationsActions;
private ExtendedFloatingActionButton markAllAsRead;
private ProgressBar progressBar;
private ProgressBar loadingMoreView;
private TextView noDataNotifications;
private SwipeRefreshLayout pullToRefresh;
private Activity activity; private Activity activity;
private Context context; private Context context;
private TinyDB tinyDB; private TinyDB tinyDB;
private Menu menu; private Menu menu;
private int pageCurrentIndex = 1; private int resultLimit;
private int pageResultLimit; private int pageSize;
private String currentFilterMode = "unread"; private String currentFilterMode = "unread";
private final String TAG = Constants.tagNotifications;
private String instanceToken;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
@ -77,194 +73,202 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 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); setHasOptionsMenu(true);
activity = requireActivity(); activity = requireActivity();
context = getContext(); context = getContext();
tinyDB = TinyDB.getInstance(context); tinyDB = TinyDB.getInstance(context);
pageResultLimit = Constants.getCurrentResultLimit(context); String loginUid = tinyDB.getString("loginUid");
tinyDB.putString("notificationsFilterState", currentFilterMode); instanceToken = "token " + tinyDB.getString(loginUid + "-token");
markAllAsRead = fragmentNotificationsBinding.markAllAsRead; resultLimit = Constants.getCurrentResultLimit(context);
noDataNotifications = fragmentNotificationsBinding.noDataNotifications; tinyDB.putString("notificationsFilterState", currentFilterMode);
loadingMoreView = fragmentNotificationsBinding.loadingMoreView;
progressBar = fragmentNotificationsBinding.progressBar;
notificationThreads = new ArrayList<>(); notificationThreads = new ArrayList<>();
notificationsActions = new NotificationsActions(context); notificationsActions = new NotificationsActions(context);
notificationsAdapter = new NotificationsAdapter(context, notificationThreads, this, this); notificationsAdapter = new NotificationsAdapter(context, notificationThreads, this, this);
RecyclerView recyclerView = fragmentNotificationsBinding.notifications;
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context); 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); viewBinding.notifications.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager); viewBinding.notifications.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(notificationsAdapter); viewBinding.notifications.setAdapter(notificationsAdapter);
recyclerView.addItemDecoration(dividerItemDecoration); viewBinding.notifications.addItemDecoration(dividerItemDecoration);
recyclerView.addOnScrollListener(new InfiniteScrollListener(pageResultLimit, linearLayoutManager) {
@Override viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
public void onScrolledToEnd(int firstVisibleItemPosition) { viewBinding.pullToRefresh.setRefreshing(false);
loadInitial(resultLimit);
pageCurrentIndex++; notificationsAdapter.notifyDataChanged();
loadNotifications(true); }, 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 @Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if(currentFilterMode.equalsIgnoreCase("unread")) { if(currentFilterMode.equalsIgnoreCase("unread")) {
if(dy > 0 && viewBinding.markAllAsRead.isShown()) {
if(dy > 0 && markAllAsRead.isShown()) { viewBinding.markAllAsRead.setVisibility(View.GONE);
}
markAllAsRead.setVisibility(View.GONE); else if(dy < 0) {
} else if(dy < 0) { viewBinding.markAllAsRead.setVisibility(View.VISIBLE);
markAllAsRead.setVisibility(View.VISIBLE);
} }
} }
} }
@Override @Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState); super.onScrollStateChanged(recyclerView, newState);
} }
}); });
markAllAsRead.setOnClickListener(v1 -> { viewBinding.markAllAsRead.setOnClickListener(v1 -> {
Thread thread = new Thread(() -> { Thread thread = new Thread(() -> {
try { try {
if(notificationsActions.setAllNotificationsRead(new Date())) { if(notificationsActions.setAllNotificationsRead(new Date())) {
activity.runOnUiThread(() -> { activity.runOnUiThread(() -> {
Toasty.success(context, getString(R.string.markedNotificationsAsRead)); Toasty.success(context, getString(R.string.markedNotificationsAsRead));
loadNotifications(true); loadInitial(resultLimit);
}); });
} }
} }
catch(IOException e) { catch(IOException e) {
activity.runOnUiThread(() -> Toasty.error(context, getString(R.string.genericError))); activity.runOnUiThread(() -> Toasty.error(context, getString(R.string.genericError)));
Log.e("onError", e.toString()); Log.e("onError", e.toString());
} }
}); });
thread.start(); thread.start();
}); });
pullToRefresh = fragmentNotificationsBinding.pullToRefresh; viewBinding.pullToRefresh.setOnRefreshListener(() -> {
pullToRefresh.setOnRefreshListener(() -> { loadInitial(resultLimit);
pageCurrentIndex = 1;
loadNotifications(false);
}); });
loadNotifications(false); loadInitial(resultLimit);
return fragmentNotificationsBinding.getRoot(); return viewBinding.getRoot();
} }
private void loadNotifications(boolean append) { private void loadInitial(int resultLimit) {
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");
notificationThreads.clear();
notificationsAdapter.notifyDataChanged();
viewBinding.progressBar.setVisibility(View.VISIBLE);
notificationThreads.clear();
String[] filter = tinyDB.getString("notificationsFilterState").equals("read") ? String[] filter = tinyDB.getString("notificationsFilterState").equals("read") ?
new String[]{"pinned", "read"} : new String[]{"pinned", "read"} :
new String[]{"pinned", "unread"}; new String[]{"pinned", "unread"};
viewBinding.pullToRefresh.setRefreshing(false);
Call<List<NotificationThread>> call = RetrofitClient Call<List<NotificationThread>> call = RetrofitClient
.getApiInterface(context) .getApiInterface(context)
.getNotificationThreads(instanceToken, false, filter, .getNotificationThreads(instanceToken, false, filter,
Constants.defaultOldestTimestamp, "", Constants.defaultOldestTimestamp, "",
pageCurrentIndex, pageResultLimit); 1, resultLimit);
call.enqueue(new Callback<List<NotificationThread>>() { call.enqueue(new Callback<List<NotificationThread>>() {
@Override @Override
public void onResponse(@NonNull Call<List<NotificationThread>> call, @NonNull Response<List<NotificationThread>> response) { public void onResponse(@NonNull Call<List<NotificationThread>> call, @NonNull Response<List<NotificationThread>> response) {
if(response.isSuccessful()) {
if(response.code() == 200) { if(response.body() != null && response.body().size() > 0) {
notificationThreads.addAll(response.body());
assert response.body() != null; notificationsAdapter.notifyDataChanged();
viewBinding.noDataNotifications.setVisibility(View.GONE);
if(!append) {
notificationThreads.clear();
} }
else {
notificationThreads.addAll(response.body()); notificationsAdapter.notifyDataChanged();
notificationsAdapter.notifyDataSetChanged(); viewBinding.noDataNotifications.setVisibility(View.VISIBLE);
}
} else { viewBinding.progressBar.setVisibility(View.GONE);
}
Log.e("onError", String.valueOf(response.code())); 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(); onCleanup();
} }
@Override @Override
public void onFailure(@NonNull Call<List<NotificationThread>> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<List<NotificationThread>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
Log.e("onError", t.toString());
onCleanup(); 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<List<NotificationThread>> call = RetrofitClient.getApiInterface(context)
.getNotificationThreads(instanceToken, false, filter,
Constants.defaultOldestTimestamp, "",
page, resultLimit);
call.enqueue(new Callback<List<NotificationThread>>() {
@Override
public void onResponse(@NonNull Call<List<NotificationThread>> call, @NonNull Response<List<NotificationThread>> response) {
if(response.code() == 200) {
assert response.body() != null;
List<NotificationThread> 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<List<NotificationThread>> 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() { private void changeFilterMode() {
int filterIcon = currentFilterMode.equalsIgnoreCase("read") ? int filterIcon = currentFilterMode.equalsIgnoreCase("read") ?
@ -274,11 +278,10 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap
menu.getItem(0).setIcon(filterIcon); menu.getItem(0).setIcon(filterIcon);
if(currentFilterMode.equalsIgnoreCase("read")) { if(currentFilterMode.equalsIgnoreCase("read")) {
viewBinding.markAllAsRead.setVisibility(View.GONE);
markAllAsRead.setVisibility(View.GONE); }
} else { else {
viewBinding.markAllAsRead.setVisibility(View.VISIBLE);
markAllAsRead.setVisibility(View.VISIBLE);
} }
} }
@ -286,14 +289,11 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
this.menu = menu; this.menu = menu;
inflater.inflate(R.menu.filter_menu_notifications, menu); inflater.inflate(R.menu.filter_menu_notifications, menu);
currentFilterMode = tinyDB.getString("notificationsFilterState"); currentFilterMode = tinyDB.getString("notificationsFilterState");
changeFilterMode(); changeFilterMode();
super.onCreateOptionsMenu(menu, inflater); super.onCreateOptionsMenu(menu, inflater);
} }
@Override @Override
@ -305,37 +305,25 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap
bottomSheetNotificationsFilterFragment.show(getChildFragmentManager(), "notificationsFilterBottomSheet"); bottomSheetNotificationsFilterFragment.show(getChildFragmentManager(), "notificationsFilterBottomSheet");
bottomSheetNotificationsFilterFragment.setOnDismissedListener(() -> { bottomSheetNotificationsFilterFragment.setOnDismissedListener(() -> {
pageCurrentIndex = 1;
currentFilterMode = tinyDB.getString("notificationsFilterState"); currentFilterMode = tinyDB.getString("notificationsFilterState");
changeFilterMode(); changeFilterMode();
loadNotifications(false); loadInitial(resultLimit);
}); });
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@Override @Override
public void onNotificationClicked(NotificationThread notificationThread) { public void onNotificationClicked(NotificationThread notificationThread) {
Thread thread = new Thread(() -> { Thread thread = new Thread(() -> {
try { try {
if(notificationThread.isUnread()) { if(notificationThread.isUnread()) {
notificationsActions.setNotificationStatus(notificationThread, NotificationsActions.NotificationStatus.READ); notificationsActions.setNotificationStatus(notificationThread, NotificationsActions.NotificationStatus.READ);
activity.runOnUiThread(() -> loadNotifications(false)); activity.runOnUiThread(() -> loadInitial(resultLimit));
} }
} catch(IOException ignored) {} } catch(IOException ignored) {}
}); });
thread.start(); thread.start();
@ -344,31 +332,23 @@ public class NotificationsFragment extends Fragment implements NotificationsAdap
Intent intent = new Intent(context, IssueDetailActivity.class); Intent intent = new Intent(context, IssueDetailActivity.class);
String issueUrl = notificationThread.getSubject().getUrl(); String issueUrl = notificationThread.getSubject().getUrl();
tinyDB.putString("issueNumber", issueUrl.substring(issueUrl.lastIndexOf("/") + 1)); tinyDB.putString("issueNumber", issueUrl.substring(issueUrl.lastIndexOf("/") + 1));
tinyDB.putString("issueType", notificationThread.getSubject().getType()); tinyDB.putString("issueType", notificationThread.getSubject().getType());
tinyDB.putString("repoFullName", notificationThread.getRepository().getFullName()); tinyDB.putString("repoFullName", notificationThread.getRepository().getFullName());
startActivity(intent); startActivity(intent);
} }
} }
@Override @Override
public void onMoreClicked(NotificationThread notificationThread) { public void onMoreClicked(NotificationThread notificationThread) {
BottomSheetNotificationsFragment bottomSheetNotificationsFragment = new BottomSheetNotificationsFragment(); BottomSheetNotificationsFragment bottomSheetNotificationsFragment = new BottomSheetNotificationsFragment();
bottomSheetNotificationsFragment.onAttach(context, notificationThread, this); bottomSheetNotificationsFragment.onAttach(context, notificationThread, this);
bottomSheetNotificationsFragment.show(getChildFragmentManager(), "notificationsBottomSheet"); bottomSheetNotificationsFragment.show(getChildFragmentManager(), "notificationsBottomSheet");
} }
@Override @Override
public void onSelected() { public void onSelected() {
loadInitial(resultLimit);
pageCurrentIndex = 1;
loadNotifications(false);
} }
} }

View File

@ -18,7 +18,6 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.gitnex.tea4j.models.IssueComments;
import org.gitnex.tea4j.models.Releases; import org.gitnex.tea4j.models.Releases;
import org.mian.gitnex.adapters.ReleasesAdapter; import org.mian.gitnex.adapters.ReleasesAdapter;
import org.mian.gitnex.databinding.FragmentReleasesBinding; import org.mian.gitnex.databinding.FragmentReleasesBinding;

View File

@ -149,6 +149,7 @@ public class DetailFragment extends Fragment {
break; break;
} }
} }
binding.progressBar.setVisibility(View.GONE);
} }
@Override @Override

View File

@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import retrofit2.Call; import retrofit2.Call;
@ -47,7 +45,7 @@ public class FollowersFragment extends Fragment {
private FollowersAdapter adapter; private FollowersAdapter adapter;
private int pageSize; private int pageSize;
private int resultLimit = Constants.resultLimitOldGiteaInstances; private int resultLimit;
private static final String usernameBundle = ""; private static final String usernameBundle = "";
private String username; private String username;
@ -78,13 +76,7 @@ public class FollowersFragment extends Fragment {
setHasOptionsMenu(true); setHasOptionsMenu(true);
context = getContext(); context = getContext();
TinyDB tinyDb = TinyDB.getInstance(context); resultLimit = Constants.getCurrentResultLimit(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;
}
usersList = new ArrayList<>(); usersList = new ArrayList<>();
fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {

View File

@ -18,7 +18,6 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import org.gitnex.tea4j.models.UserInfo; import org.gitnex.tea4j.models.UserInfo;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.adapters.profile.FollowersAdapter;
import org.mian.gitnex.adapters.profile.FollowingAdapter; import org.mian.gitnex.adapters.profile.FollowingAdapter;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentProfileFollowersFollowingBinding; 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.Authorization;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import retrofit2.Call; import retrofit2.Call;
@ -48,7 +45,7 @@ public class FollowingFragment extends Fragment {
private FollowingAdapter adapter; private FollowingAdapter adapter;
private int pageSize; private int pageSize;
private int resultLimit = Constants.resultLimitOldGiteaInstances; private int resultLimit;
private static final String usernameBundle = ""; private static final String usernameBundle = "";
private String username; private String username;
@ -79,13 +76,7 @@ public class FollowingFragment extends Fragment {
setHasOptionsMenu(true); setHasOptionsMenu(true);
context = getContext(); context = getContext();
TinyDB tinyDb = TinyDB.getInstance(context); resultLimit = Constants.getCurrentResultLimit(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;
}
usersList = new ArrayList<>(); usersList = new ArrayList<>();
fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { fragmentProfileFollowersFollowingBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {

View File

@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import retrofit2.Call; import retrofit2.Call;
@ -47,7 +45,7 @@ public class OrganizationsFragment extends Fragment {
private OrganizationsAdapter adapter; private OrganizationsAdapter adapter;
private int pageSize; private int pageSize;
private int resultLimit = Constants.resultLimitOldGiteaInstances; private int resultLimit;
private static final String usernameBundle = ""; private static final String usernameBundle = "";
private String username; private String username;
@ -78,13 +76,7 @@ public class OrganizationsFragment extends Fragment {
setHasOptionsMenu(true); setHasOptionsMenu(true);
context = getContext(); context = getContext();
TinyDB tinyDb = TinyDB.getInstance(context); resultLimit = Constants.getCurrentResultLimit(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;
}
organizationsList = new ArrayList<>(); organizationsList = new ArrayList<>();
fragmentOrganizationsBinding.addNewOrganization.setVisibility(View.GONE); fragmentOrganizationsBinding.addNewOrganization.setVisibility(View.GONE);

View File

@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import retrofit2.Call; import retrofit2.Call;
@ -47,7 +45,7 @@ public class RepositoriesFragment extends Fragment {
private RepositoriesAdapter adapter; private RepositoriesAdapter adapter;
private int pageSize; private int pageSize;
private int resultLimit = Constants.resultLimitOldGiteaInstances; private int resultLimit;
private static final String usernameBundle = ""; private static final String usernameBundle = "";
private String username; private String username;
@ -78,13 +76,7 @@ public class RepositoriesFragment extends Fragment {
setHasOptionsMenu(true); setHasOptionsMenu(true);
context = getContext(); context = getContext();
TinyDB tinyDb = TinyDB.getInstance(context); resultLimit = Constants.getCurrentResultLimit(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;
}
reposList = new ArrayList<>(); reposList = new ArrayList<>();
fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE); fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE);

View File

@ -25,9 +25,7 @@ import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar; import org.mian.gitnex.helpers.SnackBar;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import retrofit2.Call; import retrofit2.Call;
@ -47,7 +45,7 @@ public class StarredRepositoriesFragment extends Fragment {
private StarredRepositoriesAdapter adapter; private StarredRepositoriesAdapter adapter;
private int pageSize; private int pageSize;
private int resultLimit = Constants.resultLimitOldGiteaInstances; private int resultLimit;
private static final String usernameBundle = ""; private static final String usernameBundle = "";
private String username; private String username;
@ -77,13 +75,8 @@ public class StarredRepositoriesFragment extends Fragment {
fragmentRepositoriesBinding = org.mian.gitnex.databinding.FragmentRepositoriesBinding.inflate(inflater, container, false); fragmentRepositoriesBinding = org.mian.gitnex.databinding.FragmentRepositoriesBinding.inflate(inflater, container, false);
setHasOptionsMenu(true); setHasOptionsMenu(true);
context = getContext(); 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<>(); reposList = new ArrayList<>();
fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE); fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE);

View File

@ -14,10 +14,8 @@ public class Constants {
public static final String defaultOldestTimestamp = "1970-01-01T00:00:00+00:00"; public static final String defaultOldestTimestamp = "1970-01-01T00:00:00+00:00";
public static int getCurrentResultLimit(Context context) { public static int getCurrentResultLimit(Context context) {
Version version = new Version(TinyDB.getInstance(context).getString("giteaVersion")); Version version = new Version(TinyDB.getInstance(context).getString("giteaVersion"));
return version.higherOrEqual("1.12") ? resultLimitNewGiteaInstances : resultLimitOldGiteaInstances; return version.higherOrEqual("1.12") ? resultLimitNewGiteaInstances : resultLimitOldGiteaInstances;
} }
// tags // tags
@ -30,6 +28,11 @@ public class Constants {
public static final String tagDraftsBottomSheet = "BottomSheetDraftsFragment"; public static final String tagDraftsBottomSheet = "BottomSheetDraftsFragment";
public static final String userAccountsApi = "UserAccountsApi"; public static final String userAccountsApi = "UserAccountsApi";
public static final String publicOrganizations = "PublicOrganizations"; 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 // issues variables
public static final int issuesPageInit = 1; public static final int issuesPageInit = 1;

View File

@ -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);
}

View File

@ -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<List<UserInfo>> followersList;
public LiveData<List<UserInfo>> getFollowersList(String token, Context ctx) {
followersList = new MutableLiveData<>();
loadFollowersList(token, ctx);
return followersList;
}
public static void loadFollowersList(String token, Context ctx) {
Call<List<UserInfo>> call = RetrofitClient
.getApiInterface(ctx)
.getFollowers(token, 1, 50);
call.enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> response) {
if (response.isSuccessful()) {
followersList.postValue(response.body());
} else {
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<UserInfo>> call, @NonNull Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
}

View File

@ -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<List<UserInfo>> followingList;
public LiveData<List<UserInfo>> getFollowingList(String token, Context ctx) {
followingList = new MutableLiveData<>();
loadFollowingList(token, ctx);
return followingList;
}
public static void loadFollowingList(String token, Context ctx) {
Call<List<UserInfo>> call = RetrofitClient
.getApiInterface(ctx)
.getFollowing(token, 1, 50);
call.enqueue(new Callback<List<UserInfo>>() {
@Override
public void onResponse(@NonNull Call<List<UserInfo>> call, @NonNull Response<List<UserInfo>> response) {
if (response.isSuccessful()) {
followingList.postValue(response.body());
} else {
Log.i("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<UserInfo>> call, @NonNull Throwable t) {
Log.i("onFailure", t.toString());
}
});
}
}

View File

@ -16,7 +16,9 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/notifications" android:id="@+id/notifications"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent"
android:background="?attr/primaryBackgroundColor"
android:scrollbars="vertical" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -1,103 +1,100 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:background="?attr/primaryBackgroundColor" android:background="?attr/primaryBackgroundColor"
android:orientation="vertical"> android:orientation="vertical">
<RelativeLayout
android:id="@+id/profileFrame"
android:layout_width="match_parent"
android:layout_height="200dp"
android:gravity="top"
android:orientation="vertical">
<ImageView
android:id="@+id/userAvatarBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/generalImgContentText"
android:scaleType="centerCrop" />
<LinearLayout
android:id="@+id/layoutFrameAccount"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="54dp"
android:layout_height="54dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/generalImgContentText"
android:src="@mipmap/app_logo_round" />
<TextView
android:id="@+id/userFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="18sp" />
<TextView
android:id="@+id/userLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp" />
<View
android:id="@+id/divider"
android:layout_width="50dp"
android:layout_height="1dp"
android:layout_marginBottom="10dp"
android:background="@color/colorWhite" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/userLanguageIcon"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginEnd="2dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_language"
app:tint="@color/colorWhite" />
<TextView
android:id="@+id/userLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay" android:theme="@style/AppTheme.AppBarOverlay"
app:elevation="0dp"> app:elevation="0dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:id="@+id/userAvatarBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/generalImgContentText"
android:scaleType="centerCrop" />
<LinearLayout
android:id="@+id/layoutFrameAccount"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<ImageView
android:id="@+id/userAvatar"
android:layout_width="54dp"
android:layout_height="54dp"
android:layout_marginBottom="8dp"
android:contentDescription="@string/generalImgContentText"
android:src="@mipmap/app_logo_round" />
<TextView
android:id="@+id/userFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="18sp" />
<TextView
android:id="@+id/userLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp" />
<View
android:id="@+id/divider"
android:layout_width="50dp"
android:layout_height="1dp"
android:layout_marginBottom="10dp"
android:background="@color/colorWhite" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/userLanguageIcon"
android:layout_width="wrap_content"
android:layout_height="18dp"
android:layout_marginEnd="2dp"
android:contentDescription="@string/generalImgContentText"
android:src="@drawable/ic_language"
app:tint="@color/colorWhite" />
<TextView
android:id="@+id/userLanguage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorWhite"
android:textIsSelectable="true"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/tabs" android:id="@+id/tabs"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -136,4 +133,4 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</LinearLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -13,6 +13,14 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
style="@style/Widget.MaterialComponents.LinearProgressIndicator"
app:indicatorColor="?attr/progressIndicatorColor" />
<RelativeLayout <RelativeLayout
android:id="@+id/profileFrame" android:id="@+id/profileFrame"
android:layout_width="match_parent" android:layout_width="match_parent"