From 3e010361b1d16169600dc1c78bccf0bb36e466d4 Mon Sep 17 00:00:00 2001 From: M M Arif Date: Wed, 30 Aug 2023 10:58:14 +0500 Subject: [PATCH] implement adapter, fragment, viewmodel for dashboard. Add draft icon for PRs --- .../activities/IssueDetailActivity.java | 16 +- .../gitnex/adapters/DashboardAdapter.java | 736 ++++++++++++++++++ .../gitnex/adapters/PullRequestsAdapter.java | 21 + .../gitnex/fragments/DashboardFragment.java | 84 +- .../gitnex/viewmodels/DashboardViewModel.java | 114 +++ app/src/main/res/drawable/ic_draft.xml | 48 ++ .../main/res/drawable/shape_draft_release.xml | 2 +- .../main/res/drawable/shape_pre_release.xml | 2 +- .../res/drawable/shape_stable_release.xml | 2 +- .../main/res/layout/fragment_dashboard.xml | 49 ++ .../res/layout/list_dashboard_activity.xml | 139 ++++ app/src/main/res/layout/list_pr.xml | 34 +- app/src/main/res/layout/list_releases.xml | 6 +- 13 files changed, 1221 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/org/mian/gitnex/adapters/DashboardAdapter.java create mode 100644 app/src/main/java/org/mian/gitnex/viewmodels/DashboardViewModel.java create mode 100644 app/src/main/res/drawable/ic_draft.xml create mode 100644 app/src/main/res/layout/fragment_dashboard.xml create mode 100644 app/src/main/res/layout/list_dashboard_activity.xml 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 b842d9a0..13bb5149 100644 --- a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java @@ -700,6 +700,20 @@ public class IssueDetailActivity extends BaseActivity viewBinding.issuePrState, ColorStateList.valueOf( ctx.getResources().getColor(R.color.iconIssuePrClosedColor, null))); + } else if (issue.getIssue().getTitle().contains("[WIP]") + || issue.getIssue().getTitle().contains("[wip]")) { // draft + + viewBinding.issuePrState.setImageResource(R.drawable.ic_draft); + ImageViewCompat.setImageTintList( + viewBinding.issuePrState, + ColorStateList.valueOf( + ctx.getResources().getColor(R.color.colorWhite, null))); + viewBinding.issuePrState.setBackgroundResource(R.drawable.shape_draft_release); + viewBinding.issuePrState.setPadding( + R.dimen.dimen8dp, R.dimen.dimen2dp, R.dimen.dimen8dp, R.dimen.dimen2dp); + + viewBinding.toolbarTitle.setPadding( + R.dimen.dimen16dp, R.dimen.dimen0dp, R.dimen.dimen0dp, R.dimen.dimen0dp); } else { // open viewBinding.issuePrState.setImageResource(R.drawable.ic_pull_request); @@ -1034,7 +1048,7 @@ public class IssueDetailActivity extends BaseActivity RetrofitClient.getApiInterface(this) .repoGetPullRequest(repoOwner, repoName, (long) issueIndex) .enqueue( - new Callback() { + new Callback<>() { @Override public void onResponse( diff --git a/app/src/main/java/org/mian/gitnex/adapters/DashboardAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/DashboardAdapter.java new file mode 100644 index 00000000..fde20e33 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/DashboardAdapter.java @@ -0,0 +1,736 @@ +package org.mian.gitnex.adapters; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.core.content.res.ResourcesCompat; +import androidx.core.text.HtmlCompat; +import androidx.recyclerview.widget.RecyclerView; +import com.vdurmont.emoji.EmojiParser; +import java.util.List; +import java.util.Locale; +import org.gitnex.tea4j.v2.models.Activity; +import org.mian.gitnex.R; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.ClickListener; +import org.mian.gitnex.helpers.RoundedTransformation; +import org.mian.gitnex.helpers.TimeHelper; +import org.mian.gitnex.helpers.TinyDB; + +/** + * @author M M Arif + */ +public class DashboardAdapter extends RecyclerView.Adapter { + + private final Context context; + TinyDB tinyDb; + private List activityList; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + public DashboardAdapter(List dataList, Context ctx) { + this.context = ctx; + this.activityList = dataList; + this.tinyDb = TinyDB.getInstance(ctx); + } + + @NonNull @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + return new DashboardAdapter.DashboardHolder( + inflater.inflate(R.layout.list_dashboard_activity, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (position >= getItemCount() - 1 + && isMoreDataAvailable + && !isLoading + && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + + ((DashboardAdapter.DashboardHolder) holder).bindData(activityList.get(position)); + } + + @Override + public int getItemViewType(int position) { + return position; + } + + @Override + public int getItemCount() { + return activityList.size(); + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + if (!isMoreDataAvailable) { + loadMoreListener.onLoadFinished(); + } + } + + @SuppressLint("NotifyDataSetChanged") + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + loadMoreListener.onLoadFinished(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + activityList = list; + notifyDataChanged(); + } + + public interface OnLoadMoreListener { + + void onLoadMore(); + + void onLoadFinished(); + } + + class DashboardHolder extends RecyclerView.ViewHolder { + + private final ImageView userAvatar; + private final TextView typeDetails; + private final TextView createdTime; + private final ImageView typeIcon; + private final TextView dashText; + private final LinearLayout dashTextFrame; + + private Activity activityObject; + + DashboardHolder(View itemView) { + + super(itemView); + userAvatar = itemView.findViewById(R.id.user_avatar); + typeDetails = itemView.findViewById(R.id.type_details); + typeIcon = itemView.findViewById(R.id.type_icon); + createdTime = itemView.findViewById(R.id.created_time); + dashText = itemView.findViewById(R.id.text); + dashTextFrame = itemView.findViewById(R.id.dash_text_frame); + + /*new Handler() + .postDelayed( + () -> { + if (!AppUtil.checkGhostUsers(issueObject.getUser().getLogin())) { + + issueAssigneeAvatar.setOnLongClickListener( + loginId -> { + AppUtil.copyToClipboard( + context, + issueObject.getUser().getLogin(), + context.getString( + R.string.copyLoginIdToClipBoard, + issueObject.getUser().getLogin())); + return true; + }); + + issueAssigneeAvatar.setOnClickListener( + v -> { + Intent intent = + new Intent(context, ProfileActivity.class); + intent.putExtra( + "username", + issueObject.getUser().getLogin()); + context.startActivity(intent); + }); + } + }, + 500);*/ + } + + @SuppressLint("SetTextI18n") + void bindData(Activity activity) { + + this.activityObject = activity; + Locale locale = context.getResources().getConfiguration().locale; + + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + + PicassoService.getInstance(context) + .get() + .load(activity.getActUser().getAvatarUrl()) + .placeholder(R.drawable.loader_animated) + .transform(new RoundedTransformation(imgRadius, 0)) + .resize(120, 120) + .centerCrop() + .into(userAvatar); + + String username = + "" + + activity.getActUser().getLogin() + + ""; + + String headerString = ""; + String typeString = ""; + + if (activity.getOpType().contains("repo")) { + + if (activity.getOpType().equalsIgnoreCase("create_repo")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + typeString = "created repository"; + typeIcon.setImageResource(R.drawable.ic_repo); + } else if (activity.getOpType().equalsIgnoreCase("rename_repo")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + typeString = "renamed repository from " + activity.getContent() + " to"; + typeIcon.setImageResource(R.drawable.ic_repo); + } else if (activity.getOpType().equalsIgnoreCase("star_repo")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + typeString = "starred"; + typeIcon.setImageResource(R.drawable.ic_star); + } else if (activity.getOpType().equalsIgnoreCase("transfer_repo")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + typeString = "transferred repository " + activity.getContent() + " to"; + typeIcon.setImageResource(R.drawable.ic_arrow_up); + } else if (activity.getOpType().equalsIgnoreCase("commit_repo")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + if (activity.getContent().isEmpty()) { + String branch = + "" + + activity.getRefName() + .substring( + activity.getRefName().lastIndexOf("/") + 1) + .trim() + + ""; + typeString = "created branch " + branch + " in"; + } else { + String branch = + "" + + activity.getRefName() + .substring( + activity.getRefName().lastIndexOf("/") + 1) + .trim() + + ""; + typeString = "pushed to " + branch + " at"; + } + typeIcon.setImageResource(R.drawable.ic_commit); + } + } else if (activity.getOpType().contains("issue")) { + + String id = ""; + String content = ""; + String[] contentParts = activity.getContent().split("\\|"); + if (contentParts.length > 1) { + id = contentParts[0]; + content = contentParts[1]; + dashTextFrame.setVisibility(View.VISIBLE); + dashText.setText(EmojiParser.parseToUnicode(content)); + } else { + id = contentParts[0]; + } + + if (activity.getOpType().equalsIgnoreCase("create_issue")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "opened issue"; + typeIcon.setImageResource(R.drawable.ic_issue); + } else if (activity.getOpType().equalsIgnoreCase("comment_issue")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "commented on issue"; + typeIcon.setImageResource(R.drawable.ic_comment); + } else if (activity.getOpType().equalsIgnoreCase("close_issue")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "closed issue"; + typeIcon.setImageResource(R.drawable.ic_issue_closed); + } else if (activity.getOpType().equalsIgnoreCase("reopen_issue")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "reopened issue"; + typeIcon.setImageResource(R.drawable.ic_reopen); + } + } else if (activity.getOpType().contains("pull")) { + + String id = ""; + String content = ""; + String[] contentParts = activity.getContent().split("\\|"); + if (contentParts.length > 1) { + id = contentParts[0]; + content = contentParts[1]; + dashTextFrame.setVisibility(View.VISIBLE); + dashText.setText(EmojiParser.parseToUnicode(content)); + } else { + id = contentParts[0]; + } + + if (activity.getOpType().equalsIgnoreCase("create_pull_request")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "created pull request"; + typeIcon.setImageResource(R.drawable.ic_pull_request); + } else if (activity.getOpType().equalsIgnoreCase("close_pull_request")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "closed pull request"; + typeIcon.setImageResource(R.drawable.ic_issue_closed); + } else if (activity.getOpType().equalsIgnoreCase("reopen_pull_request")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "reopened pull request"; + typeIcon.setImageResource(R.drawable.ic_reopen); + } else if (activity.getOpType().equalsIgnoreCase("merge_pull_request")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "merged pull request"; + typeIcon.setImageResource(R.drawable.ic_pull_request); + } else if (activity.getOpType().equalsIgnoreCase("approve_pull_request")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "approved"; + typeIcon.setImageResource(R.drawable.ic_done); + } else if (activity.getOpType().equalsIgnoreCase("reject_pull_request")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "suggested changes for"; + typeIcon.setImageResource(R.drawable.ic_diff); + } else if (activity.getOpType().equalsIgnoreCase("comment_pull")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "commented on pull request"; + typeIcon.setImageResource(R.drawable.ic_comment); + } else if (activity.getOpType().equalsIgnoreCase("auto_merge_pull_request")) { + + headerString = + "" + + activity.getRepo().getFullName() + + context.getResources().getString(R.string.hash) + + id + + ""; + typeString = "automatically merged pull request"; + typeIcon.setImageResource(R.drawable.ic_issue_closed); + } + } else if (activity.getOpType().contains("branch")) { + + String id = ""; + String content = ""; + String[] contentParts = activity.getContent().split("\\|"); + if (contentParts.length > 1) { + id = contentParts[0]; + content = contentParts[1]; + dashTextFrame.setVisibility(View.VISIBLE); + dashText.setText(EmojiParser.parseToUnicode(content)); + } else { + id = contentParts[0]; + } + + if (activity.getOpType().equalsIgnoreCase("delete_branch")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + + String branch = + "" + + activity.getRefName() + .substring(activity.getRefName().lastIndexOf("/") + 1) + .trim() + + ""; + + typeString = "deleted branch " + branch + " at"; + typeIcon.setImageResource(R.drawable.ic_commit); + } + } else if (activity.getOpType().contains("tag")) { + + if (activity.getOpType().equalsIgnoreCase("push_tag")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + + String branch = + "" + + activity.getRefName() + .substring(activity.getRefName().lastIndexOf("/") + 1) + .trim() + + ""; + + typeString = "pushed tag " + branch + " to"; + typeIcon.setImageResource(R.drawable.ic_commit); + } else if (activity.getOpType().equalsIgnoreCase("delete_tag")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + + String branch = + "" + + activity.getRefName() + .substring(activity.getRefName().lastIndexOf("/") + 1) + .trim() + + ""; + + typeString = "deleted tag " + branch + " from"; + typeIcon.setImageResource(R.drawable.ic_commit); + } + } else if (activity.getOpType().contains("release")) { + + if (activity.getOpType().equalsIgnoreCase("publish_release")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + + String branch = + "" + + activity.getRefName() + .substring(activity.getRefName().lastIndexOf("/") + 1) + .trim() + + ""; + + typeString = "released " + branch + " at"; + typeIcon.setImageResource(R.drawable.ic_tag); + } + } else if (activity.getOpType().contains("mirror")) { + + if (activity.getOpType().equalsIgnoreCase("mirror_sync_push")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + + typeString = "synced commits to " + headerString + " at"; + typeIcon.setImageResource(R.drawable.ic_tag); + } else if (activity.getOpType().equalsIgnoreCase("mirror_sync_create")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + + typeString = "synced new reference " + headerString + " to"; + typeIcon.setImageResource(R.drawable.ic_tag); + } else if (activity.getOpType().equalsIgnoreCase("mirror_sync_delete")) { + + headerString = + "" + + activity.getRepo().getFullName() + + ""; + + typeString = "synced and deleted reference " + headerString + " at"; + typeIcon.setImageResource(R.drawable.ic_tag); + } + } else { + dashTextFrame.setVisibility(View.GONE); + dashText.setVisibility(View.GONE); + } + + typeDetails.setText( + HtmlCompat.fromHtml( + username + " " + typeString + " " + headerString, + HtmlCompat.FROM_HTML_MODE_LEGACY)); + + /*String issueNumber_ = + "" + + context.getResources().getString(R.string.hash) + + issue.getNumber() + + ""; + issueTitle.setText( + HtmlCompat.fromHtml( + issueNumber_ + " " + EmojiParser.parseToUnicode(issue.getTitle()), + HtmlCompat.FROM_HTML_MODE_LEGACY)); + + this.issueObject = issue; + this.issueCommentsCount.setText(String.valueOf(issue.getComments())); + + Intent intentIssueDetail = + new IssueContext(issueObject, ((RepoDetailActivity) context).repository) + .getIntent(context, IssueDetailActivity.class);*/ + + /*itemView.setOnClickListener(layoutView -> context.startActivity(intentIssueDetail)); + frameLabels.setOnClickListener(v -> context.startActivity(intentIssueDetail)); + frameLabelsDots.setOnClickListener(v -> context.startActivity(intentIssueDetail));*/ + + /*LinearLayout.LayoutParams params = + new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + params.setMargins(0, 0, 15, 0); + + Typeface typeface = AppUtil.getTypeface(context);*/ + + this.createdTime.setText(TimeHelper.formatTime(activity.getCreated(), locale)); + this.createdTime.setOnClickListener( + new ClickListener( + TimeHelper.customDateFormatForToastDateFormat(activity.getCreated()), + context)); + + /*if (issue.getLabels() != null) { + + if (!tinyDb.getBoolean("showLabelsInList", false)) { // default + + labelsScrollViewWithText.setVisibility(View.GONE); + labelsScrollViewDots.setVisibility(View.VISIBLE); + frameLabelsDots.removeAllViews(); + + for (int i = 0; i < issue.getLabels().size(); i++) { + + String labelColor = issue.getLabels().get(i).getColor(); + int color = Color.parseColor("#" + labelColor); + + ImageView labelsView = new ImageView(context); + frameLabelsDots.setOrientation(LinearLayout.HORIZONTAL); + frameLabelsDots.setGravity(Gravity.START | Gravity.TOP); + labelsView.setLayoutParams(params); + + TextDrawable drawable = + TextDrawable.builder() + .beginConfig() + .useFont(typeface) + .width(54) + .height(54) + .endConfig() + .buildRound("", color); + + labelsView.setImageDrawable(drawable); + frameLabelsDots.addView(labelsView); + } + } else { + + labelsScrollViewDots.setVisibility(View.GONE); + labelsScrollViewWithText.setVisibility(View.VISIBLE); + frameLabels.removeAllViews(); + + for (int i = 0; i < issue.getLabels().size(); i++) { + + String labelColor = issue.getLabels().get(i).getColor(); + String labelName = issue.getLabels().get(i).getName(); + int color = Color.parseColor("#" + labelColor); + + ImageView labelsView = new ImageView(context); + frameLabels.setOrientation(LinearLayout.HORIZONTAL); + frameLabels.setGravity(Gravity.START | Gravity.TOP); + labelsView.setLayoutParams(params); + + int height = AppUtil.getPixelsFromDensity(context, 20); + int textSize = AppUtil.getPixelsFromScaledDensity(context, 12); + + TextDrawable drawable = + TextDrawable.builder() + .beginConfig() + .useFont(typeface) + .textColor(new ColorInverter().getContrastColor(color)) + .fontSize(textSize) + .width( + LabelWidthCalculator.calculateLabelWidth( + labelName, + typeface, + textSize, + AppUtil.getPixelsFromDensity(context, 8))) + .height(height) + .endConfig() + .buildRoundRect( + labelName, + color, + AppUtil.getPixelsFromDensity(context, 18)); + + labelsView.setImageDrawable(drawable); + frameLabels.addView(labelsView); + } + } + }*/ + + /*if (issue.getComments() > 15) { + commentIcon.setImageDrawable( + ContextCompat.getDrawable(context, R.drawable.ic_flame)); + commentIcon.setColorFilter( + context.getResources().getColor(R.color.releasePre, null)); + }*/ + + /*this.issueCreatedTime.setText(TimeHelper.formatTime(issue.getCreatedAt(), locale)); + this.issueCreatedTime.setOnClickListener( + new ClickListener( + TimeHelper.customDateFormatForToastDateFormat(issue.getCreatedAt()), + context));*/ + } + } +} diff --git a/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java index 2fa28bc5..ca2a9937 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/PullRequestsAdapter.java @@ -3,6 +3,7 @@ package org.mian.gitnex.adapters; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; +import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.Typeface; import android.os.Handler; @@ -18,6 +19,7 @@ import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; import androidx.core.text.HtmlCompat; +import androidx.core.widget.ImageViewCompat; import androidx.recyclerview.widget.RecyclerView; import com.amulyakhare.textdrawable.TextDrawable; import com.vdurmont.emoji.EmojiParser; @@ -106,6 +108,7 @@ public class PullRequestsAdapter extends RecyclerView.Adapter"; + if (pullRequest.getTitle().contains("[WIP]") + || pullRequest.getTitle().contains("[wip]")) { + this.issuePrState.setVisibility(View.VISIBLE); + this.issuePrState.setImageResource(R.drawable.ic_draft); + ImageViewCompat.setImageTintList( + this.issuePrState, + ColorStateList.valueOf( + context.getResources().getColor(R.color.colorWhite, null))); + this.issuePrState.setBackgroundResource(R.drawable.shape_draft_release); + this.issuePrState.setPadding( + R.dimen.dimen8dp, R.dimen.dimen2dp, R.dimen.dimen8dp, R.dimen.dimen2dp); + this.prTitle.setPadding( + R.dimen.dimen16dp, R.dimen.dimen0dp, R.dimen.dimen0dp, R.dimen.dimen0dp); + } else { + this.issuePrState.setVisibility(View.GONE); + } + this.prTitle.setText( HtmlCompat.fromHtml( prNumber_ + " " + EmojiParser.parseToUnicode(pullRequest.getTitle()), diff --git a/app/src/main/java/org/mian/gitnex/fragments/DashboardFragment.java b/app/src/main/java/org/mian/gitnex/fragments/DashboardFragment.java index 2aa7e0c4..d773a650 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/DashboardFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/DashboardFragment.java @@ -9,60 +9,68 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; import java.util.ArrayList; import java.util.List; +import org.gitnex.tea4j.v2.models.Activity; import org.mian.gitnex.R; +import org.mian.gitnex.activities.BaseActivity; import org.mian.gitnex.activities.MainActivity; -import org.mian.gitnex.adapters.NotesAdapter; -import org.mian.gitnex.database.models.Notes; -import org.mian.gitnex.databinding.FragmentNotesBinding; +import org.mian.gitnex.adapters.DashboardAdapter; +import org.mian.gitnex.databinding.FragmentDashboardBinding; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.viewmodels.DashboardViewModel; /** * @author M M Arif */ public class DashboardFragment extends Fragment { - private FragmentNotesBinding binding; - private Context ctx; - private NotesAdapter adapter; - private List notesList; + protected TinyDB tinyDB; + private DashboardViewModel dashboardViewModel; + private FragmentDashboardBinding binding; + private DashboardAdapter adapter; + private List activityList; + private int page = 1; + private String username; @Override public View onCreateView( @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - binding = FragmentNotesBinding.inflate(inflater, container, false); + binding = FragmentDashboardBinding.inflate(inflater, container, false); - ctx = getContext(); + Context ctx = getContext(); setHasOptionsMenu(true); ((MainActivity) requireActivity()) .setActionBarTitle(getResources().getString(R.string.dashboard)); - notesList = new ArrayList<>(); + activityList = new ArrayList<>(); + + dashboardViewModel = new ViewModelProvider(this).get(DashboardViewModel.class); + + username = ((BaseActivity) requireActivity()).getAccount().getAccount().getUserName(); binding.recyclerView.setHasFixedSize(true); binding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx)); - binding.recyclerView.setPadding(0, 0, 0, 220); - binding.recyclerView.setClipToPadding(false); - - adapter = new NotesAdapter(ctx, notesList); + adapter = new DashboardAdapter(activityList, ctx); binding.pullToRefresh.setOnRefreshListener( () -> new Handler(Looper.getMainLooper()) .postDelayed( () -> { - notesList.clear(); + activityList.clear(); binding.pullToRefresh.setRefreshing(false); binding.progressBar.setVisibility(View.VISIBLE); - // fetchDataAsync(); + fetchDataAsync(username); }, 250)); - // fetchDataAsync(); + fetchDataAsync(username); return binding.getRoot(); } @@ -70,6 +78,46 @@ public class DashboardFragment extends Fragment { @Override public void onResume() { super.onResume(); - // fetchDataAsync(); + fetchDataAsync(username); + } + + private void fetchDataAsync(String username) { + + dashboardViewModel + .getActivitiesList(username, getContext(), binding) + .observe( + getViewLifecycleOwner(), + activityListMain -> { + adapter = new DashboardAdapter(activityListMain, getContext()); + adapter.setLoadMoreListener( + new DashboardAdapter.OnLoadMoreListener() { + + @Override + public void onLoadMore() { + + page += 1; + dashboardViewModel.loadMoreActivities( + username, page, getContext(), adapter, binding); + binding.progressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onLoadFinished() { + + binding.progressBar.setVisibility(View.GONE); + } + }); + + if (adapter.getItemCount() > 0) { + binding.recyclerView.setAdapter(adapter); + binding.noData.setVisibility(View.GONE); + } else { + adapter.notifyDataChanged(); + binding.recyclerView.setAdapter(adapter); + binding.noData.setVisibility(View.VISIBLE); + } + + binding.progressBar.setVisibility(View.GONE); + }); } } diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/DashboardViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/DashboardViewModel.java new file mode 100644 index 00000000..e5efd68b --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/viewmodels/DashboardViewModel.java @@ -0,0 +1,114 @@ +package org.mian.gitnex.viewmodels; + +import android.content.Context; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; +import java.util.List; +import org.gitnex.tea4j.v2.models.Activity; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.DashboardAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.FragmentDashboardBinding; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.Toasty; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * @author M M Arif + */ +public class DashboardViewModel extends ViewModel { + + private MutableLiveData> activityList; + private int resultLimit; + + public LiveData> getActivitiesList( + String username, Context ctx, FragmentDashboardBinding binding) { + + activityList = new MutableLiveData<>(); + resultLimit = Constants.getCurrentResultLimit(ctx); + loadActivityList(username, ctx, binding); + return activityList; + } + + public void loadActivityList(String username, Context ctx, FragmentDashboardBinding binding) { + + Call> call = + RetrofitClient.getApiInterface(ctx) + .userListActivityFeeds(username, false, null, 1, resultLimit); + + call.enqueue( + new Callback<>() { + + @Override + public void onResponse( + @NonNull Call> call, + @NonNull Response> response) { + + if (response.isSuccessful()) { + activityList.postValue(response.body()); + } else { + binding.progressBar.setVisibility(View.GONE); + 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)); + } + }); + } + + public void loadMoreActivities( + String username, + int page, + Context ctx, + DashboardAdapter adapter, + FragmentDashboardBinding binding) { + + Call> call = + RetrofitClient.getApiInterface(ctx) + .userListActivityFeeds(username, false, null, page, resultLimit); + + call.enqueue( + new Callback<>() { + + @Override + public void onResponse( + @NonNull Call> call, + @NonNull Response> response) { + + if (response.isSuccessful()) { + + List list = activityList.getValue(); + assert list != null; + assert response.body() != null; + + if (response.body().size() != 0) { + list.addAll(response.body()); + adapter.updateList(list); + } else { + adapter.setMoreDataAvailable(false); + } + } else { + binding.progressBar.setVisibility(View.GONE); + 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_draft.xml b/app/src/main/res/drawable/ic_draft.xml new file mode 100644 index 00000000..e63c7a9b --- /dev/null +++ b/app/src/main/res/drawable/ic_draft.xml @@ -0,0 +1,48 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/shape_draft_release.xml b/app/src/main/res/drawable/shape_draft_release.xml index 66e02aef..65c5db56 100644 --- a/app/src/main/res/drawable/shape_draft_release.xml +++ b/app/src/main/res/drawable/shape_draft_release.xml @@ -8,7 +8,7 @@ + android:radius="@dimen/dimen6dp"> diff --git a/app/src/main/res/drawable/shape_pre_release.xml b/app/src/main/res/drawable/shape_pre_release.xml index 1f250589..4a08a2a0 100644 --- a/app/src/main/res/drawable/shape_pre_release.xml +++ b/app/src/main/res/drawable/shape_pre_release.xml @@ -8,7 +8,7 @@ + android:radius="@dimen/dimen6dp"> diff --git a/app/src/main/res/drawable/shape_stable_release.xml b/app/src/main/res/drawable/shape_stable_release.xml index 9f3dedc6..c74d7fc3 100644 --- a/app/src/main/res/drawable/shape_stable_release.xml +++ b/app/src/main/res/drawable/shape_stable_release.xml @@ -8,7 +8,7 @@ + android:radius="@dimen/dimen6dp"> diff --git a/app/src/main/res/layout/fragment_dashboard.xml b/app/src/main/res/layout/fragment_dashboard.xml new file mode 100644 index 00000000..c14c07c8 --- /dev/null +++ b/app/src/main/res/layout/fragment_dashboard.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_dashboard_activity.xml b/app/src/main/res/layout/list_dashboard_activity.xml new file mode 100644 index 00000000..6949b03f --- /dev/null +++ b/app/src/main/res/layout/list_dashboard_activity.xml @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/list_pr.xml b/app/src/main/res/layout/list_pr.xml index 29d657bc..6a9b206f 100644 --- a/app/src/main/res/layout/list_pr.xml +++ b/app/src/main/res/layout/list_pr.xml @@ -54,15 +54,33 @@ android:layout_height="wrap_content" android:orientation="vertical"> - + android:orientation="horizontal"> + + + + + +