diff --git a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java index 7158caae..69e8dc99 100644 --- a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java @@ -124,6 +124,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt } } }); + private int page = 1; @Override public void onCreate(Bundle savedInstanceState) { @@ -164,10 +165,11 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + page = 1; viewBinding.pullToRefresh.setRefreshing(false); - issueCommentsModel.loadIssueComments(repoOwner, repoName, issueIndex, ctx); + issueCommentsModel.loadIssueComments(repoOwner, repoName, issueIndex, ctx, null); - }, 500)); + }, 50)); Typeface myTypeface = AppUtil.getTypeface(this); viewBinding.toolbarTitle.setTypeface(myTypeface); @@ -459,7 +461,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt viewBinding.scrollViewComments.post(() -> { - issueCommentsModel.loadIssueComments(repoOwner, repoName, issueIndex, ctx); + issueCommentsModel.loadIssueComments(repoOwner, repoName, issueIndex, ctx, null); commentEdited = false; }); } @@ -488,9 +490,26 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt bundle.putInt("issueNumber", issueIndex); adapter = new IssueCommentsAdapter(ctx, bundle, issueCommentsMain, getSupportFragmentManager(), this::onResume, issue); + adapter.setLoadMoreListener(new IssueCommentsAdapter.OnLoadMoreListener() { + @Override + public void onLoadMore() { + + page += 1; + issueCommentsModel.loadMoreIssueComments(owner, repo, index, ctx, page, adapter); + viewBinding.progressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onLoadFinished() { + + viewBinding.progressBar.setVisibility(View.GONE); + } + }); + + adapter.notifyDataChanged(); viewBinding.recyclerView.setAdapter(adapter); - + viewBinding.progressBar.setVisibility(View.GONE); }); } diff --git a/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java index 63715dcd..041ba5b2 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java @@ -54,16 +54,18 @@ import retrofit2.Callback; * @author M M Arif */ -public class IssueCommentsAdapter extends RecyclerView.Adapter { +public class IssueCommentsAdapter extends RecyclerView.Adapter { private final Context context; private final TinyDB tinyDB; private final Bundle bundle; - private final List issuesComments; private final FragmentManager fragmentManager; private final Runnable onInteractedListener; private final Locale locale; private final IssueContext issue; + private List issuesComments; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; public IssueCommentsAdapter(Context ctx, Bundle bundle, List issuesCommentsMain, FragmentManager fragmentManager, Runnable onInteractedListener, IssueContext issue) { @@ -88,7 +90,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter call = RetrofitClient.getApiInterface(ctx).issueDeleteComment(issue.getRepository().getOwner(), issue.getRepository().getName(), (long) commentId); - call.enqueue(new Callback() { + call.enqueue(new Callback<>() { @Override public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { @@ -129,280 +131,47 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter TimeHelper.customDateFormatForToastDateFormat(issueComment.getCreatedAt())); - } - else if(timeFormat.equals("normal")) { - informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreatedAt(), locale, "normal", context)); - } - - if(!issueComment.getCreatedAt().equals(issueComment.getUpdatedAt())) { - if(informationBuilder != null) { - informationBuilder.append(context.getString(R.string.colorfulBulletSpan)).append(context.getString(R.string.modifiedText)); - } - } + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); } - // label view in timeline - if(issueComment.getType().equalsIgnoreCase("label")) { + ((IssueCommentsAdapter.IssueCommentViewHolder) holder).bindData(issuesComments.get(position)); + } - holder.labelView.setVisibility(View.VISIBLE); + @SuppressLint("NotifyDataSetChanged") + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + loadMoreListener.onLoadFinished(); + } - int color = Color.parseColor("#" + issueComment.getLabel().getColor()); - - ImageView labelsView = new ImageView(context); - - int height = AppUtil.getPixelsFromDensity(context, 20); - int textSize = AppUtil.getPixelsFromScaledDensity(context, 12); - - TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).textColor(new ColorInverter().getContrastColor(color)).fontSize(textSize) - .width(LabelWidthCalculator.calculateLabelWidth(issueComment.getLabel().getName(), Typeface.DEFAULT, textSize, AppUtil.getPixelsFromDensity(context, 10))).height(height).endConfig() - .buildRoundRect(issueComment.getLabel().getName(), color, AppUtil.getPixelsFromDensity(context, 18)); - - labelsView.setImageDrawable(drawable); - - TextView start = new TextView(context); - TextView end = new TextView(context); - - if(issueComment.getBody().equals("")){ - start.setText(issueComment.getUser().getLogin() + " removed the "); - } - else { - start.setText(issueComment.getUser().getLogin() + " added the "); - } - end.setText(" label " + informationBuilder); - end.setTextSize(12); - start.setTextSize(12); - - holder.labelData.addView(start); - holder.labelData.addView(labelsView); - holder.labelData.addView(end); - } - else { - holder.labelView.setVisibility(View.GONE); + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + if(!isMoreDataAvailable) { + loadMoreListener.onLoadFinished(); } + } - // pull/push/commit data view in timeline - if(issueComment.getType().equalsIgnoreCase("pull_push")) { + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } - holder.commitView.setVisibility(View.VISIBLE); + public void updateList(List list) { + issuesComments = list; + notifyDataChanged(); + } - TextView start = new TextView(context); - - start.setText(issueComment.getUser().getLogin() + " added commit " + informationBuilder); - start.setTextSize(12); - - holder.commitData.addView(start); - } - else { - holder.commitView.setVisibility(View.GONE); - } - - // assignees data view in timeline - if(issueComment.getType().equalsIgnoreCase("assignees")) { - - holder.assigneesView.setVisibility(View.VISIBLE); - TextView start = new TextView(context); - - if(issueComment.getUser().getLogin().equalsIgnoreCase(issueComment.getAssignee().getLogin())) { - start.setText(issueComment.getUser().getLogin() + " self-assigned this " + informationBuilder); - } - else if(issueComment.isRemovedAssignee()) { - - if(issueComment.getUser().getLogin().equalsIgnoreCase(issueComment.getAssignee().getLogin())) { - start.setText(issueComment.getUser().getLogin() + " removed their assignment " + informationBuilder); - } - else { - start.setText(issueComment.getAssignee().getLogin() + " was unassigned by " + issueComment.getUser().getLogin() + " " + informationBuilder); - } - } - else { - start.setText(issueComment.getAssignee().getLogin() + " was assigned by " + issueComment.getUser().getLogin() + " " + informationBuilder); - } - - - start.setTextSize(12); - - holder.assigneesData.addView(start); - } - else { - holder.assigneesView.setVisibility(View.GONE); - } - - // milestone data view in timeline - if(issueComment.getType().equalsIgnoreCase("milestone")) { - - holder.milestoneView.setVisibility(View.VISIBLE); - - TextView start = new TextView(context); - - if(issueComment.getMilestone() != null) { - start.setText(issueComment.getUser().getLogin() + " added this to the " + issueComment.getMilestone().getTitle() + " milestone " + informationBuilder); - } - else { - start.setText(issueComment.getUser().getLogin() + " removed this from the " + issueComment.getOldMilestone().getTitle() + " milestone " + informationBuilder); - } - start.setTextSize(12); - - holder.milestoneData.addView(start); - } - else { - holder.milestoneView.setVisibility(View.GONE); - } - - // status view in timeline - if(issueComment.getType().equalsIgnoreCase("close") || issueComment.getType().equalsIgnoreCase("reopen") || issueComment.getType().equalsIgnoreCase("merge_pull") || issueComment.getType().equalsIgnoreCase("commit_ref")) { - - holder.statusView.setVisibility(View.VISIBLE); - - TextView start = new TextView(context); - - if(issue.getIssueType().equalsIgnoreCase("Issue")) { - if(issueComment.getType().equals("close")) { - start.setText(issueComment.getUser().getLogin() + " closed this issue " + informationBuilder); - holder.statusIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); - } - else if(issueComment.getType().equalsIgnoreCase("reopen")) { - start.setText(issueComment.getUser().getLogin() + " reopened this issue " + informationBuilder); - } - } - else if(issue.getIssueType().equalsIgnoreCase("Pull")) { - if(issueComment.getType().equalsIgnoreCase("close")) { - start.setText(issueComment.getUser().getLogin() + " closed this pull request " + informationBuilder); - holder.statusIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request)); - holder.statusIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); - } - else if(issueComment.getType().equalsIgnoreCase("merge_pull")) { - start.setText(issueComment.getUser().getLogin() + " merged this pull request " + informationBuilder); - holder.statusIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request)); - holder.statusIcon.setColorFilter(context.getResources().getColor(R.color.iconPrMergedColor, null)); - } - else if(issueComment.getType().equalsIgnoreCase("commit_ref")) { - start.setText(issueComment.getUser().getLogin() + " referenced this issue from a commit " + issueComment.getRefCommitSha() + " " + informationBuilder); - holder.statusIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_bookmark)); - } - else { - start.setText(issue.getIssueType() + " reopened this pull request " + informationBuilder); - holder.statusIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request)); - } - } - start.setTextSize(12); - - holder.statusData.addView(start); - } - else { - holder.statusView.setVisibility(View.GONE); - } - - // review data view in timeline - if(issueComment.getType().equalsIgnoreCase("review") || issueComment.getType().equalsIgnoreCase("review_request")) { - - holder.reviewView.setVisibility(View.VISIBLE); - - TextView start = new TextView(context); - - /*if(issueComment.getType().equalsIgnoreCase("review")) { - start.setText(issueComment.getUser().getLogin() + " approved these changes " + informationBuilder); - } - else*/ if(issueComment.getType().equalsIgnoreCase("review_request")) { - start.setText(issueComment.getUser().getLogin() + " requested review from " + issueComment.getAssignee().getLogin() + " " + informationBuilder); - holder.reviewIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_unwatch)); - } - start.setTextSize(12); - - holder.reviewData.addView(start); - } - else { - holder.reviewView.setVisibility(View.GONE); - } - - // change title data view in timeline - if(issueComment.getType().equalsIgnoreCase("change_title")) { - - holder.changeTitleView.setVisibility(View.VISIBLE); - - TextView start = new TextView(context); - start.setText(issueComment.getUser().getLogin() + " changed title from " + issueComment.getOldTitle() + " to " + issueComment.getNewTitle() + " " + informationBuilder); - start.setTextSize(12); - - holder.changeTitleData.addView(start); - } - else { - holder.changeTitleView.setVisibility(View.GONE); - } - - // lock/unlock data view in timeline - if(issueComment.getType().equalsIgnoreCase("lock") || issueComment.getType().equalsIgnoreCase("unlock")) { - - holder.lockView.setVisibility(View.VISIBLE); - - TextView start = new TextView(context); - - if(issueComment.getType().equalsIgnoreCase("lock")) { - start.setText(issueComment.getUser().getLogin() + " locked as " + issueComment.getBody() + " and limited conversation to collaborators " + informationBuilder); - } - else if(issueComment.getType().equalsIgnoreCase("unlock")) { - start.setText(issueComment.getUser().getLogin() + " unlocked this conversation " + informationBuilder); - holder.lockIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_key)); - } - start.setTextSize(12); - - holder.lockData.addView(start); - } - else { - holder.lockView.setVisibility(View.GONE); - } - - // comment data view in timeline - if(issueComment.getType().equalsIgnoreCase("comment")) { - - holder.author.setText(issueComment.getUser().getLogin()); - - PicassoService.getInstance(context).get().load(issueComment.getUser().getAvatarUrl()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)) - .resize(AppUtil.getPixelsFromDensity(context, 35), AppUtil.getPixelsFromDensity(context, 35)).centerCrop().into(holder.avatar); - - Markdown.render(context, EmojiParser.parseToUnicode(issueComment.getBody()), holder.comment, issue.getRepository()); - - holder.information.setText(informationBuilder); - - Bundle bundle1 = new Bundle(); - bundle1.putAll(bundle); - bundle1.putInt("commentId", Math.toIntExact(issueComment.getId())); - - ReactionList reactionList = new ReactionList(context, bundle1); - - holder.commentReactionBadges.addView(reactionList); - reactionList.setOnReactionAddedListener(() -> { - - if(holder.commentReactionBadges.getVisibility() != View.VISIBLE) { - holder.commentReactionBadges.post(() -> holder.commentReactionBadges.setVisibility(View.VISIBLE)); - } - }); - } - else { - holder.commentView.setVisibility(View.GONE); - } + @Override + public int getItemViewType(int position) { + return position; } @Override @@ -415,6 +184,14 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter { @@ -640,6 +369,374 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter TimeHelper.customDateFormatForToastDateFormat(issueComment.getCreatedAt())); + } + else if(timeFormat.equals("normal")) { + informationBuilder = new StringBuilder(TimeHelper.formatTime(issueComment.getCreatedAt(), locale, "normal", context)); + } + + if(!issueComment.getCreatedAt().equals(issueComment.getUpdatedAt())) { + if(informationBuilder != null) { + informationBuilder.append(context.getString(R.string.colorfulBulletSpan)).append(context.getString(R.string.modifiedText)); + } + } + } + + // label view in timeline + if(issueComment.getType().equalsIgnoreCase("label")) { + + ImageView labelsView = new ImageView(context); + int color = Color.parseColor("#" + issueComment.getLabel().getColor()); + int height = AppUtil.getPixelsFromDensity(context, 20); + int textSize = AppUtil.getPixelsFromScaledDensity(context, 12); + + TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).textColor(new ColorInverter().getContrastColor(color)).fontSize(textSize) + .width(LabelWidthCalculator.calculateLabelWidth(issueComment.getLabel().getName(), Typeface.DEFAULT, textSize, AppUtil.getPixelsFromDensity(context, 10))).height(height).endConfig() + .buildRoundRect(issueComment.getLabel().getName(), color, AppUtil.getPixelsFromDensity(context, 18)); + + labelsView.setImageDrawable(drawable); + + TextView start = new TextView(context); + TextView end = new TextView(context); + + if(issueComment.getBody().equals("")) { + start.setText(issueComment.getUser().getLogin() + " removed the "); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + else { + start.setText(issueComment.getUser().getLogin() + " added the "); + } + end.setText(" label " + informationBuilder); + end.setTextSize(12); + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_tag)); + timelineData.addView(start); + timelineData.addView(labelsView); + timelineData.addView(end); + } + // pull/push/commit data view in timeline + else if(issueComment.getType().equalsIgnoreCase("pull_push")) { + + TextView start = new TextView(context); + + start.setText(issueComment.getUser().getLogin() + " added commit " + informationBuilder); + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_person)); + timelineData.addView(start); + } + // assignees data view in timeline + else if(issueComment.getType().equalsIgnoreCase("assignees")) { + + TextView start = new TextView(context); + + if(issueComment.isRemovedAssignee()) { + + if(issueComment.getUser().getLogin().equalsIgnoreCase(issueComment.getAssignee().getLogin())) { + start.setText(issueComment.getUser().getLogin() + " removed their assignment " + informationBuilder); + } + else { + start.setText(issueComment.getAssignee().getLogin() + " was unassigned by " + issueComment.getUser().getLogin() + " " + informationBuilder); + } + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + else { + if(issueComment.getUser().getLogin().equalsIgnoreCase(issueComment.getAssignee().getLogin())) { + start.setText(issueComment.getUser().getLogin() + " self-assigned this " + informationBuilder); + } + else { + start.setText(issueComment.getAssignee().getLogin() + " was assigned by " + issueComment.getUser().getLogin() + " " + informationBuilder); + } + } + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_person)); + timelineData.addView(start); + } + // milestone data view in timeline + else if(issueComment.getType().equalsIgnoreCase("milestone")) { + + TextView start = new TextView(context); + + if(issueComment.getMilestone() != null) { + start.setText(issueComment.getUser().getLogin() + " added this to the " + issueComment.getMilestone().getTitle() + " milestone " + informationBuilder); + } + else { + start.setText(issueComment.getUser().getLogin() + " removed this from the " + issueComment.getOldMilestone().getTitle() + " milestone " + informationBuilder); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_milestone)); + timelineData.addView(start); + } + // status view in timeline + else if(issueComment.getType().equalsIgnoreCase("close") || issueComment.getType().equalsIgnoreCase("reopen") || issueComment.getType().equalsIgnoreCase("merge_pull") || issueComment.getType() + .equalsIgnoreCase("commit_ref")) { + + TextView start = new TextView(context); + + if(issue.getIssueType().equalsIgnoreCase("Issue")) { + if(issueComment.getType().equals("close")) { + start.setText(issueComment.getUser().getLogin() + " closed this issue " + informationBuilder); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + else if(issueComment.getType().equalsIgnoreCase("reopen")) { + start.setText(issueComment.getUser().getLogin() + " reopened this issue " + informationBuilder); + } + else if(issueComment.getType().equalsIgnoreCase("commit_ref")) { + start.setText(issueComment.getUser().getLogin() + " referenced this issue from a commit " + issueComment.getRefCommitSha() + " " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_bookmark)); + } + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_issue)); + } + else if(issue.getIssueType().equalsIgnoreCase("Pull")) { + if(issueComment.getType().equalsIgnoreCase("close")) { + start.setText(issueComment.getUser().getLogin() + " closed this pull request " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request)); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + else if(issueComment.getType().equalsIgnoreCase("merge_pull")) { + start.setText(issueComment.getUser().getLogin() + " merged this pull request " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request)); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconPrMergedColor, null)); + } + else if(issueComment.getType().equalsIgnoreCase("commit_ref")) { + start.setText(issueComment.getUser().getLogin() + " referenced this issue from a commit " + issueComment.getRefCommitSha() + " " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_bookmark)); + } + else { + start.setText(issue.getIssueType() + " reopened this pull request " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_pull_request)); + } + } + start.setTextSize(12); + + timelineData.addView(start); + } + // review data view in timeline + else if(issueComment.getType().equalsIgnoreCase("review_request") || issueComment.getType().equalsIgnoreCase("review") || issueComment.getType().equalsIgnoreCase("dismiss_review")) { + + TextView start = new TextView(context); + + if(issueComment.getType().equalsIgnoreCase("review")) { + timelineView.setVisibility(View.GONE); + } + else if(issueComment.getType().equalsIgnoreCase("dismiss_review")) { + timelineView.setVisibility(View.GONE); + } + else if(issueComment.getType().equalsIgnoreCase("review_request")) { + start.setText(issueComment.getUser().getLogin() + " requested review from " + issueComment.getAssignee().getLogin() + " " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_unwatch)); + } + start.setTextSize(12); + + timelineData.addView(start); + } + // change title data view in timeline + else if(issueComment.getType().equalsIgnoreCase("change_title")) { + + TextView start = new TextView(context); + start.setText(issueComment.getUser().getLogin() + " changed title from " + issueComment.getOldTitle() + " to " + issueComment.getNewTitle() + " " + informationBuilder); + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_edit)); + timelineData.addView(start); + } + // lock/unlock data view in timeline + else if(issueComment.getType().equalsIgnoreCase("lock") || issueComment.getType().equalsIgnoreCase("unlock")) { + + TextView start = new TextView(context); + + if(issueComment.getType().equalsIgnoreCase("lock")) { + start.setText(issueComment.getUser().getLogin() + " locked as " + issueComment.getBody() + " and limited conversation to collaborators " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_lock)); + } + else if(issueComment.getType().equalsIgnoreCase("unlock")) { + start.setText(issueComment.getUser().getLogin() + " unlocked this conversation " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_key)); + } + start.setTextSize(12); + + timelineData.addView(start); + } + // dependency data view in timeline + else if(issueComment.getType().equalsIgnoreCase("add_dependency") || issueComment.getType().equalsIgnoreCase("remove_dependency")) { + + TextView start = new TextView(context); + + if(issueComment.getType().equalsIgnoreCase("add_dependency")) { + start.setText( + issueComment.getUser().getLogin() + " added a new dependency " + context.getResources().getString(R.string.hash) + issueComment.getDependentIssue().getNumber() + " " + informationBuilder); + } + else if(issueComment.getType().equalsIgnoreCase("remove_dependency")) { + start.setText(issueComment.getUser().getLogin() + " removed a dependency " + context.getResources().getString(R.string.hash) + issueComment.getDependentIssue().getNumber() + " " + informationBuilder); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_dependency)); + timelineData.addView(start); + } + // project data view in timeline + else if(issueComment.getType().equalsIgnoreCase("project") || issueComment.getType().equalsIgnoreCase("project_board")) { + + TextView start = new TextView(context); + + if(issueComment.getProjectId() > 0) { + start.setText(issueComment.getUser().getLogin() + " added this to a project " + informationBuilder); + } + else { + start.setText(issueComment.getUser().getLogin() + " removed this from a project " + informationBuilder); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_kanban)); + timelineData.addView(start); + } + // due date/deadline data view in timeline + else if(issueComment.getType().equalsIgnoreCase("added_deadline") || issueComment.getType().equalsIgnoreCase("modified_deadline") || issueComment.getType().equalsIgnoreCase("removed_deadline")) { + + TextView start = new TextView(context); + + if(issueComment.getType().equalsIgnoreCase("added_deadline")) { + start.setText(issueComment.getUser().getLogin() + " added the due date " + issueComment.getBody() + " " + informationBuilder); + } + else if(issueComment.getType().equalsIgnoreCase("modified_deadline")) { + start.setText(issueComment.getUser().getLogin() + " modified the due date to " + issueComment.getBody().split("\\|")[0] + " from " + issueComment.getBody().split("\\|")[1] + " " + informationBuilder); + } + else if(issueComment.getType().equalsIgnoreCase("removed_deadline")) { + start.setText(issueComment.getUser().getLogin() + " removed the due date " + issueComment.getBody() + " " + informationBuilder); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_clock)); + timelineData.addView(start); + } + // branch data view in timeline + else if(issueComment.getType().equalsIgnoreCase("change_target_branch") || issueComment.getType().equalsIgnoreCase("delete_branch")) { + + TextView start = new TextView(context); + + if(issueComment.getType().equalsIgnoreCase("change_target_branch")) { + start.setText(issueComment.getUser().getLogin() + " changed target branch from " + issueComment.getOldRef() + " to " + issueComment.getNewRef() + " " + informationBuilder); + } + else if(issueComment.getType().equalsIgnoreCase("delete_branch")) { + start.setText(issueComment.getUser().getLogin() + " deleted branch " + issueComment.getOldRef() + " " + informationBuilder); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_branch)); + timelineData.addView(start); + } + // time tracking data view in timeline + else if(issueComment.getType().equalsIgnoreCase("start_tracking") || issueComment.getType().equalsIgnoreCase("stop_tracking") || issueComment.getType() + .equalsIgnoreCase("cancel_tracking") || issueComment.getType().equalsIgnoreCase("add_time_manual") || issueComment.getType().equalsIgnoreCase("delete_time_manual")) { + + TextView start = new TextView(context); + + if(issueComment.getType().equalsIgnoreCase("start_tracking")) { + start.setText(issueComment.getUser().getLogin() + " started working " + informationBuilder); + } + else if(issueComment.getType().equalsIgnoreCase("stop_tracking")) { + start.setText(issueComment.getUser().getLogin() + " stopped time tracking " + informationBuilder); + } + else if(issueComment.getType().equalsIgnoreCase("cancel_tracking")) { + start.setText(issueComment.getUser().getLogin() + " cancelled time tracking " + informationBuilder); + timelineIcon.setColorFilter(context.getResources().getColor(R.color.iconIssuePrClosedColor, null)); + } + start.setTextSize(12); + + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_clock)); + timelineData.addView(start); + } + // issue/pr refs data view in timeline + else if(issueComment.getType().equalsIgnoreCase("change_issue_ref") || issueComment.getType().equalsIgnoreCase("issue_ref") || issueComment.getType().equalsIgnoreCase("comment_ref") || issueComment.getType() + .equalsIgnoreCase("pull_ref")) { + + TextView start = new TextView(context); + + if(issueComment.getType().equalsIgnoreCase("change_issue_ref")) { + start.setText(issueComment.getUser().getLogin() + " added reference " + issueComment.getNewRef() + " " + informationBuilder); + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_branch)); + } + else if(issueComment.getType().equalsIgnoreCase("comment_ref") || issueComment.getType().equalsIgnoreCase("issue_ref") || issueComment.getType().equalsIgnoreCase("pull_ref")) { + + if(issue.getIssueType().equalsIgnoreCase("Issue")) { + start.setText( + issueComment.getUser().getLogin() + " referenced this issue in " + context.getResources().getString(R.string.hash) + issueComment.getRefIssue().getNumber() + " " + informationBuilder); + } + else if(issue.getIssueType().equalsIgnoreCase("Pull")) { + start.setText( + issueComment.getUser().getLogin() + " referenced this pull request in " + context.getResources().getString(R.string.hash) + issueComment.getRefIssue().getNumber() + " " + informationBuilder); + } + timelineIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_bookmark)); + } + start.setTextSize(12); + + timelineData.addView(start); + } + // code data view in timeline + else if(issueComment.getType().equalsIgnoreCase("code")) { + timelineView.setVisibility(View.GONE); + } + // schedule pr view in timeline + else if(issueComment.getType().equalsIgnoreCase("pull_scheduled_merge") || issueComment.getType().equalsIgnoreCase("pull_cancel_scheduled_merge")) { + timelineView.setVisibility(View.GONE); + } + else { + timelineView.setVisibility(View.GONE); + } + + // comment data view in timeline + if(issueComment.getType().equalsIgnoreCase("comment")) { + + author.setText(issueComment.getUser().getLogin()); + + PicassoService.getInstance(context).get().load(issueComment.getUser().getAvatarUrl()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)) + .resize(AppUtil.getPixelsFromDensity(context, 35), AppUtil.getPixelsFromDensity(context, 35)).centerCrop().into(avatar); + + Markdown.render(context, EmojiParser.parseToUnicode(issueComment.getBody()), comment, issue.getRepository()); + + information.setText(informationBuilder); + + Bundle bundle1 = new Bundle(); + bundle1.putAll(bundle); + bundle1.putInt("commentId", Math.toIntExact(issueComment.getId())); + + ReactionList reactionList = new ReactionList(context, bundle1); + + commentReactionBadges.addView(reactionList); + reactionList.setOnReactionAddedListener(() -> { + + if(commentReactionBadges.getVisibility() != View.VISIBLE) { + commentReactionBadges.post(() -> commentReactionBadges.setVisibility(View.VISIBLE)); + } + }); + } + else { + commentView.setVisibility(View.GONE); + } + } + } } diff --git a/app/src/main/java/org/mian/gitnex/fragments/MyIssuesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/MyIssuesFragment.java index 896e6dba..9cb77571 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/MyIssuesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/MyIssuesFragment.java @@ -26,13 +26,13 @@ import org.mian.gitnex.viewmodels.IssuesViewModel; public class MyIssuesFragment extends Fragment { + public String state = "open"; + public boolean assignedToMe = false; private IssuesViewModel issuesViewModel; private FragmentIssuesBinding fragmentIssuesBinding; private ExploreIssuesAdapter adapter; private int page = 1; private Menu menu; - public String state = "open"; - public boolean assignedToMe = false; @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -75,8 +75,6 @@ public class MyIssuesFragment extends Fragment { return fragmentIssuesBinding.getRoot(); } - ; - private void fetchDataAsync(String query, String state, boolean assignedToMe) { issuesViewModel.getIssuesList(query, "issues", true, state, assignedToMe, getContext()).observe(getViewLifecycleOwner(), issuesListMain -> { diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/IssueCommentsViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/IssueCommentsViewModel.java index 9bd5f235..1bf0bb99 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/IssueCommentsViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/IssueCommentsViewModel.java @@ -7,7 +7,9 @@ import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; import org.gitnex.tea4j.v2.models.TimelineComment; import org.mian.gitnex.R; +import org.mian.gitnex.adapters.IssueCommentsAdapter; import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Toasty; import java.util.List; import retrofit2.Call; @@ -21,22 +23,19 @@ import retrofit2.Response; public class IssueCommentsViewModel extends ViewModel { private MutableLiveData> issueComments; + private int resultLimit; public LiveData> getIssueCommentList(String owner, String repo, int index, Context ctx) { issueComments = new MutableLiveData<>(); - loadIssueComments(owner, repo, index, ctx); - - return issueComments; - } - - public void loadIssueComments(String owner, String repo, int index, Context ctx) { + resultLimit = Constants.getCurrentResultLimit(ctx); loadIssueComments(owner, repo, index, ctx, null); + return issueComments; } public void loadIssueComments(String owner, String repo, int index, Context ctx, Runnable onLoadingFinished) { - Call> call = RetrofitClient.getApiInterface(ctx).issueGetCommentsAndTimeline(owner, repo, (long) index, null, null, 25, null); + Call> call = RetrofitClient.getApiInterface(ctx).issueGetCommentsAndTimeline(owner, repo, (long) index, null, 1, resultLimit, null); call.enqueue(new Callback<>() { @@ -62,4 +61,39 @@ public class IssueCommentsViewModel extends ViewModel { }); } + public void loadMoreIssueComments(String owner, String repo, int index, Context ctx, int page, IssueCommentsAdapter adapter) { + + Call> call = RetrofitClient.getApiInterface(ctx).issueGetCommentsAndTimeline(owner, repo, (long) index, null, page, resultLimit, null); + + call.enqueue(new Callback<>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + if(response.body() != null) { + + List list = issueComments.getValue(); + assert list != null; + assert response.body() != null; + + list.addAll(response.body()); + } + else { + adapter.setMoreDataAvailable(false); + } + } + else { + Toasty.error(ctx, ctx.getString(R.string.genericError)); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError)); + } + }); + } + } diff --git a/app/src/main/res/drawable/ic_branch.xml b/app/src/main/res/drawable/ic_branch.xml index 936bfb56..9765ef6f 100644 --- a/app/src/main/res/drawable/ic_branch.xml +++ b/app/src/main/res/drawable/ic_branch.xml @@ -3,32 +3,46 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - - - - + + + + + + diff --git a/app/src/main/res/drawable/ic_clock.xml b/app/src/main/res/drawable/ic_clock.xml new file mode 100644 index 00000000..d165ae17 --- /dev/null +++ b/app/src/main/res/drawable/ic_clock.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/ic_dependency.xml b/app/src/main/res/drawable/ic_dependency.xml new file mode 100644 index 00000000..1dd9a72e --- /dev/null +++ b/app/src/main/res/drawable/ic_dependency.xml @@ -0,0 +1,41 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_fork.xml b/app/src/main/res/drawable/ic_fork.xml index c039c3f8..02fb7b50 100644 --- a/app/src/main/res/drawable/ic_fork.xml +++ b/app/src/main/res/drawable/ic_fork.xml @@ -3,16 +3,39 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - - - + + + + + diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml new file mode 100644 index 00000000..bd820821 --- /dev/null +++ b/app/src/main/res/drawable/ic_history.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/ic_kanban.xml b/app/src/main/res/drawable/ic_kanban.xml new file mode 100644 index 00000000..e8f40f30 --- /dev/null +++ b/app/src/main/res/drawable/ic_kanban.xml @@ -0,0 +1,34 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_reset.xml b/app/src/main/res/drawable/ic_refresh.xml similarity index 85% rename from app/src/main/res/drawable/ic_reset.xml rename to app/src/main/res/drawable/ic_refresh.xml index 409ba9b1..b6cb15b8 100644 --- a/app/src/main/res/drawable/ic_reset.xml +++ b/app/src/main/res/drawable/ic_refresh.xml @@ -4,10 +4,10 @@ android:viewportWidth="24" android:viewportHeight="24"> + android:strokeLineCap="round" + android:strokeLineJoin="round" /> diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml deleted file mode 100644 index ff53349e..00000000 --- a/app/src/main/res/drawable/ic_update.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - diff --git a/app/src/main/res/layout/activity_issue_detail.xml b/app/src/main/res/layout/activity_issue_detail.xml index 57202ab2..b817b8cd 100644 --- a/app/src/main/res/layout/activity_issue_detail.xml +++ b/app/src/main/res/layout/activity_issue_detail.xml @@ -1,19 +1,18 @@ - + android:background="?attr/primaryBackgroundColor" + android:orientation="vertical"> + android:theme="@style/Widget.AppCompat.SearchView" + app:elevation="@dimen/dimen0dp"> + android:src="@drawable/ic_issue" + android:visibility="gone" /> + android:textSize="@dimen/dimen20sp" /> @@ -46,31 +45,31 @@ + app:indicatorColor="?attr/progressIndicatorColor" /> + android:layout_margin="@dimen/dimen16dp" + android:backgroundTint="?attr/fabColor" + android:contentDescription="@string/commentButtonText" + android:text="@string/commentButtonText" + android:textColor="@color/colorWhite" + app:icon="@drawable/ic_reply" + app:iconTint="@color/colorWhite" /> + android:layout_height="match_parent" + android:layout_marginTop="@dimen/dimen64dp"> + android:paddingStart="@dimen/dimen8dp" + android:paddingTop="@dimen/dimen2dp" + android:paddingEnd="@dimen/dimen8dp" + android:paddingBottom="@dimen/dimen8dp"> + app:cardCornerRadius="@dimen/dimen12dp" + app:cardElevation="@dimen/dimen0dp"> + android:contentDescription="@string/generalImgContentText" /> + android:textSize="@dimen/dimen16sp" /> + android:contentDescription="@string/generalImgContentText" + app:srcCompat="@drawable/ic_calendar" /> + android:textSize="@dimen/dimen14sp" /> @@ -185,8 +187,8 @@ + android:contentDescription="@string/generalImgContentText" + app:srcCompat="@drawable/ic_milestone" /> + android:textSize="@dimen/dimen14sp" /> + android:scrollbarThumbHorizontal="@android:color/transparent"> + android:orientation="horizontal"> + android:textSize="@dimen/dimen14sp" /> + android:scrollbarThumbHorizontal="@android:color/transparent"> + android:layout_marginTop="@dimen/dimen10dp" + android:orientation="horizontal"> + android:layout_marginTop="@dimen/dimen10dp" + android:orientation="horizontal"> + android:textSize="@dimen/dimen12sp" + android:visibility="gone" /> + android:visibility="gone" /> @@ -289,9 +291,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/issueTimeFrame" - android:visibility="gone" android:layout_marginTop="@dimen/dimen10dp" - android:orientation="horizontal"/> + android:orientation="horizontal" + android:visibility="gone" /> @@ -302,15 +304,15 @@ + android:layout_below="@+id/mainThreadCard" + android:background="?attr/primaryBackgroundColor"> + android:clipToPadding="false" + android:paddingBottom="@dimen/dimen72dp" /> diff --git a/app/src/main/res/layout/bottom_sheet_single_issue.xml b/app/src/main/res/layout/bottom_sheet_single_issue.xml index 1d4fc8bd..a9280e45 100644 --- a/app/src/main/res/layout/bottom_sheet_single_issue.xml +++ b/app/src/main/res/layout/bottom_sheet_single_issue.xml @@ -1,6 +1,5 @@ - + android:orientation="horizontal" /> + android:background="?attr/dividerColor" /> + android:textSize="16sp" /> @@ -73,7 +72,7 @@ android:textSize="16sp" android:visibility="gone" app:drawableTopCompat="@drawable/ic_file" - app:layout_alignSelf="flex_start"/> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:drawableTopCompat="@drawable/ic_refresh" + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> @@ -202,7 +201,7 @@ android:layout_width="match_parent" android:layout_height="4dp" android:layout_marginBottom="16dp" - android:background="?attr/dividerColor"/> + android:background="?attr/dividerColor" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> + app:layout_alignSelf="flex_start" /> diff --git a/app/src/main/res/layout/list_issue_comments.xml b/app/src/main/res/layout/list_issue_comments.xml index 1793dcab..d9d6dac7 100644 --- a/app/src/main/res/layout/list_issue_comments.xml +++ b/app/src/main/res/layout/list_issue_comments.xml @@ -10,18 +10,18 @@ + android:foreground="?android:attr/selectableItemBackground" + android:orientation="vertical" + android:padding="@dimen/dimen12dp"> + app:cardCornerRadius="@dimen/dimen12dp" + app:cardElevation="@dimen/dimen0dp"> + tools:srcCompat="@tools:sample/avatars" /> @@ -63,7 +63,7 @@ android:singleLine="true" android:textColor="?attr/primaryTextColor" android:textSize="14sp" - android:textStyle="bold"/> + android:textStyle="bold" /> + android:textSize="12sp" /> + android:contentDescription="@string/menuContentDesc" + app:srcCompat="@drawable/ic_dotted_menu_horizontal" /> @@ -92,333 +92,59 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="12dp" - android:textColor="?attr/primaryTextColor" - android:textIsSelectable="true" android:autoLink="web" + android:textColor="?attr/primaryTextColor" android:textColorLink="@color/lightBlue" - android:textSize="14sp"/> + android:textIsSelectable="true" + android:textSize="14sp" /> + android:orientation="horizontal" + android:visibility="gone" /> - - - - - - - - - - - - + android:layout_marginBottom="@dimen/dimen4dp" + android:orientation="horizontal"> + app:cardElevation="@dimen/dimen0dp"> + android:contentDescription="@string/generalImgContentText" + android:src="@drawable/ic_history" + tools:srcCompat="@drawable/ic_history" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_marginEnd="@dimen/dimen4dp" + android:gravity="center" + android:orientation="horizontal" /> diff --git a/app/src/main/res/layout/list_most_visited_repos.xml b/app/src/main/res/layout/list_most_visited_repos.xml index c115c966..705bf547 100644 --- a/app/src/main/res/layout/list_most_visited_repos.xml +++ b/app/src/main/res/layout/list_most_visited_repos.xml @@ -9,18 +9,18 @@ android:paddingBottom="@dimen/dimen4dp"> + android:foreground="?android:attr/selectableItemBackground" + android:orientation="vertical" + android:padding="@dimen/dimen12dp"> + android:src="@drawable/ic_android" /> + tools:text="@string/orgName" /> @@ -57,13 +57,13 @@ android:text="@string/repoName" android:textColor="?attr/primaryTextColor" android:textSize="@dimen/dimen16sp" - android:textStyle="bold"/> + android:textStyle="bold" /> + android:layout_marginBottom="@dimen/dimen8dp" /> + app:tint="?attr/iconsColor" /> + tools:text="@string/repoStars" /> + app:srcCompat="@drawable/ic_delete" + app:tint="?attr/iconsColor" /> diff --git a/app/src/main/res/menu/reset_menu.xml b/app/src/main/res/menu/reset_menu.xml index 0b676b25..c7b7fde4 100644 --- a/app/src/main/res/menu/reset_menu.xml +++ b/app/src/main/res/menu/reset_menu.xml @@ -4,9 +4,9 @@ + android:title="@string/menuContentDesc" + app:showAsAction="ifRoom" />