Optimize fragments, add filters, fix search and clean up (#439)

Code Reformat

hide not found message

Refactor issues, remove fastadapter.

fix swipe back filter icon issue, fix crash on issues with faster swiping

Change filter icon based on selection, empty the list for progress bar, check for gitea version to pass limit and other improvements

Separate menu and interface for pr

Add filter bottom sheet to PRs, issues

Fix search/filter pull requests

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/439
Reviewed-by: opyale <opyale@noreply.gitea.io>
This commit is contained in:
M M Arif 2020-04-23 20:40:13 +00:00 committed by 6543
parent 625e60f2e2
commit 0ee5b43996
20 changed files with 2349 additions and 2524 deletions

View File

@ -1,19 +1,10 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import com.google.android.material.tabs.TabLayout;
import com.google.gson.JsonElement;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import retrofit2.Call;
import retrofit2.Callback;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -23,13 +14,23 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import com.google.gson.JsonElement;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BottomSheetIssuesFilterFragment;
import org.mian.gitnex.fragments.BottomSheetPullRequestFilterFragment;
import org.mian.gitnex.fragments.BottomSheetRepoFragment; import org.mian.gitnex.fragments.BottomSheetRepoFragment;
import org.mian.gitnex.fragments.BranchesFragment; import org.mian.gitnex.fragments.BranchesFragment;
import org.mian.gitnex.fragments.CollaboratorsFragment; import org.mian.gitnex.fragments.CollaboratorsFragment;
import org.mian.gitnex.fragments.FilesFragment; import org.mian.gitnex.fragments.FilesFragment;
import org.mian.gitnex.fragments.IssuesMainFragment; import org.mian.gitnex.fragments.IssuesFragment;
import org.mian.gitnex.fragments.LabelsFragment; import org.mian.gitnex.fragments.LabelsFragment;
import org.mian.gitnex.fragments.MilestonesFragment; import org.mian.gitnex.fragments.MilestonesFragment;
import org.mian.gitnex.fragments.PullRequestsFragment; import org.mian.gitnex.fragments.PullRequestsFragment;
@ -42,413 +43,480 @@ import org.mian.gitnex.models.WatchRepository;
import org.mian.gitnex.util.AppUtil; import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.Objects; import java.util.Objects;
import android.net.Uri; import retrofit2.Call;
import retrofit2.Callback;
/** /**
* Author M M Arif * Author M M Arif
*/ */
public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoFragment.BottomSheetListener { public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoFragment.BottomSheetListener, BottomSheetIssuesFilterFragment.BottomSheetListener, BottomSheetPullRequestFilterFragment.BottomSheetListener {
private TextView textViewBadgeIssue; private TextView textViewBadgeIssue;
private TextView textViewBadgePull; private TextView textViewBadgePull;
private TextView textViewBadgeRelease; private TextView textViewBadgeRelease;
@Override private FragmentRefreshListener fragmentRefreshListener;
protected int getLayoutResourceId(){ private FragmentRefreshListenerPr fragmentRefreshListenerPr;
return R.layout.activity_repo_detail;
}
@Override // issues interface
public void onCreate(Bundle savedInstanceState) { public FragmentRefreshListener getFragmentRefreshListener() {
super.onCreate(savedInstanceState);
TinyDB tinyDb = new TinyDB(getApplicationContext()); return fragmentRefreshListener;
String repoFullName = tinyDb.getString("repoFullName"); }
String[] parts = repoFullName.split("/");
String repoName1 = parts[1];
final String instanceUrl = tinyDb.getString("instanceUrl");
final String repoOwner = parts[0];
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String appLocale = tinyDb.getString("locale");
AppUtil.setAppLocale(getResources(), appLocale);
Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(repoName1);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
ViewPager mViewPager = findViewById(R.id.container);
mViewPager.setAdapter(mSectionsPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
toolbarTitle.setText(repoName1);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for (int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for (int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
// only show Collaborators if you have permission to
final View collaboratorTab = vg.getChildAt(8);
if (tinyDb.getBoolean("isRepoAdmin")) {
collaboratorTab.setVisibility(View.VISIBLE);
}
else {
collaboratorTab.setVisibility(View.GONE);
}
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
if(tinyDb.getBoolean("enableCounterBadges")) {
@SuppressLint("InflateParams") View tabHeader2 = LayoutInflater.from(this).inflate(R.layout.badge_issue, null);
textViewBadgeIssue = tabHeader2.findViewById(R.id.counterBadgeIssue);
@SuppressLint("InflateParams") View tabHeader4 = LayoutInflater.from(this).inflate(R.layout.badge_pull, null);
textViewBadgePull = tabHeader4.findViewById(R.id.counterBadgePull);
@SuppressLint("InflateParams") View tabHeader6 = LayoutInflater.from(this).inflate(R.layout.badge_release, null);
textViewBadgeRelease = tabHeader6.findViewById(R.id.counterBadgeRelease);
textViewBadgeIssue.setVisibility(View.GONE);
textViewBadgePull.setVisibility(View.GONE);
textViewBadgeRelease.setVisibility(View.GONE);
getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
ColorStateList textColor = tabLayout.getTabTextColors();
// issue count
if (textViewBadgeIssue.getText() != "") {
TabLayout.Tab tabOpenIssues = tabLayout.getTabAt(2);
Objects.requireNonNull(tabLayout.getTabAt(2)).setCustomView(tabHeader2);
assert tabOpenIssues != null;
TextView openIssueTabView = Objects.requireNonNull(tabOpenIssues.getCustomView()).findViewById(R.id.counterBadgeIssueText);
openIssueTabView.setTextColor(textColor);
}
// pull count
if (textViewBadgePull.getText() != "") { // only show if API returned a number
Objects.requireNonNull(tabLayout.getTabAt(3)).setCustomView(tabHeader4);
TabLayout.Tab tabOpenPulls = tabLayout.getTabAt(3);
assert tabOpenPulls != null;
TextView openPullTabView = Objects.requireNonNull(tabOpenPulls.getCustomView()).findViewById(R.id.counterBadgePullText);
openPullTabView.setTextColor(textColor);
}
// release count
if (VersionCheck.compareVersion("1.11.5", tinyDb.getString("giteaVersion")) < 1) {
if(textViewBadgeRelease.getText() != "") { // only show if API returned a number
Objects.requireNonNull(tabLayout.getTabAt(5)).setCustomView(tabHeader6);
TabLayout.Tab tabOpenRelease = tabLayout.getTabAt(5);
assert tabOpenRelease != null;
TextView openReleaseTabView = Objects.requireNonNull(tabOpenRelease.getCustomView()).findViewById(R.id.counterBadgeReleaseText);
openReleaseTabView.setTextColor(textColor);
}
}
}
checkRepositoryStarStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
checkRepositoryWatchStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(tinyDb.getBoolean("enableCounterIssueBadge")) {
getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.repo_dotted_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
finish();
return true;
case R.id.repoMenu:
BottomSheetRepoFragment bottomSheet = new BottomSheetRepoFragment();
bottomSheet.show(getSupportFragmentManager(), "repoBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onButtonClicked(String text) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String instanceUrlWithProtocol = "https://" + tinyDb.getString("instanceUrlRaw");
if(!tinyDb.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDb.getString("instanceUrlWithProtocol");
}
Uri url = Uri.parse(instanceUrlWithProtocol + "/" + repoFullName);
switch (text) {
case "label":
startActivity(new Intent(RepoDetailActivity.this, CreateLabelActivity.class));
break;
case "newIssue":
startActivity(new Intent(RepoDetailActivity.this, CreateIssueActivity.class));
break;
case "newMilestone":
startActivity(new Intent(RepoDetailActivity.this, CreateMilestoneActivity.class));
break;
case "addCollaborator":
startActivity(new Intent(RepoDetailActivity.this, AddCollaboratorToRepositoryActivity.class));
break;
case "createRelease":
startActivity(new Intent(RepoDetailActivity.this, CreateReleaseActivity.class));
break;
case "openWebRepo":
Intent i = new Intent(Intent.ACTION_VIEW, url);
startActivity(i);
break;
case "shareRepo":
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, url);
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(sharingIntent, url.toString()));
break;
case "newFile":
startActivity(new Intent(RepoDetailActivity.this, CreateFileActivity.class));
break;
}
}
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
Fragment fragment = null;
switch (position) {
case 0: // information
return RepoInfoFragment.newInstance(repoOwner, repoName);
case 1: // files
return FilesFragment.newInstance(repoOwner, repoName);
case 2: // issues
fragment = new IssuesMainFragment();
break;
case 3: // pull requests
fragment = new PullRequestsFragment();
break;
case 4: // branches
return BranchesFragment.newInstance(repoOwner, repoName);
case 5: // releases
return ReleasesFragment.newInstance(repoOwner, repoName);
case 6: // milestones
return MilestonesFragment.newInstance(repoOwner, repoName);
case 7: // labels
return LabelsFragment.newInstance(repoOwner, repoName);
case 8: // collaborators
return CollaboratorsFragment.newInstance(repoOwner, repoName);
}
assert fragment != null;
return fragment;
}
@Override
public int getCount() {
return 9;
}
}
private void getRepoInfo(String instanceUrl, String token, final String owner, String repo) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<UserRepositories> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getUserRepository(token, owner, repo);
call.enqueue(new Callback<UserRepositories>() {
@Override
public void onResponse(@NonNull Call<UserRepositories> call, @NonNull retrofit2.Response<UserRepositories> response) {
UserRepositories repoInfo = response.body();
if (response.isSuccessful()) {
if (response.code() == 200) {
if(tinyDb.getBoolean("enableCounterBadges")) {
assert repoInfo != null;
if(repoInfo.getOpen_issues_count() != null) {
textViewBadgeIssue.setVisibility(View.VISIBLE);
textViewBadgeIssue.setText(repoInfo.getOpen_issues_count());
}
if(repoInfo.getOpen_pull_count() != null) {
textViewBadgePull.setVisibility(View.VISIBLE);
textViewBadgePull.setText(repoInfo.getOpen_pull_count());
}
if(repoInfo.getRelease_count() != null) {
textViewBadgeRelease.setVisibility(View.VISIBLE);
textViewBadgeRelease.setText(repoInfo.getRelease_count());
}
}
} public void setFragmentRefreshListener(FragmentRefreshListener fragmentRefreshListener) {
} this.fragmentRefreshListener = fragmentRefreshListener;
else { }
Log.e("onFailure", String.valueOf(response.code()));
}
} public interface FragmentRefreshListener {
@Override void onRefresh(String text);
public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
}); }
} // pr interface
public FragmentRefreshListenerPr getFragmentRefreshListenerPr() {
private void checkRepositoryStarStatus(String instanceUrl, String instanceToken, final String owner, String repo) { return fragmentRefreshListenerPr;
}
Call<JsonElement> call; public void setFragmentRefreshListenerPr(FragmentRefreshListenerPr fragmentRefreshListenerPr) {
call = RetrofitClient this.fragmentRefreshListenerPr = fragmentRefreshListenerPr;
.getInstance(instanceUrl, getApplicationContext()) }
.getApiInterface()
.checkRepoStarStatus(instanceToken, owner, repo);
call.enqueue(new Callback<JsonElement>() { public interface FragmentRefreshListenerPr {
@Override void onRefresh(String text);
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
TinyDB tinyDb = new TinyDB(getApplicationContext()); }
tinyDb.putInt("repositoryStarStatus", response.code());
} @Override
protected int getLayoutResourceId() {
@Override return R.layout.activity_repo_detail;
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) { }
Log.e("onFailure", t.toString());
}
});
} @Override
public void onCreate(Bundle savedInstanceState) {
private void checkRepositoryWatchStatus(String instanceUrl, String instanceToken, final String owner, String repo) { super.onCreate(savedInstanceState);
Call<WatchRepository> call; TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
String repoName1 = parts[1];
call = RetrofitClient final String instanceUrl = tinyDb.getString("instanceUrl");
.getInstance(instanceUrl, getApplicationContext()) final String repoOwner = parts[0];
.getApiInterface() final String loginUid = tinyDb.getString("loginUid");
.checkRepoWatchStatus(instanceToken, owner, repo); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
call.enqueue(new Callback<WatchRepository>() { tinyDb.putString("repoIssuesState", "open");
tinyDb.putString("repoPrState", "open");
@Override String appLocale = tinyDb.getString("locale");
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) { AppUtil.setAppLocale(getResources(), appLocale);
TinyDB tinyDb = new TinyDB(getApplicationContext()); Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = toolbar.findViewById(R.id.toolbar_title);
if(response.code() == 200) { setSupportActionBar(toolbar);
assert response.body() != null; Objects.requireNonNull(getSupportActionBar()).setTitle(repoName1);
if(response.body().getSubscribed()) { getSupportActionBar().setDisplayHomeAsUpEnabled(true);
tinyDb.putBoolean("repositoryWatchStatus", true);
}
}
else {
tinyDb.putBoolean("repositoryWatchStatus", false);
}
} SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
@Override ViewPager mViewPager = findViewById(R.id.container);
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) { mViewPager.setAdapter(mSectionsPagerAdapter);
Log.e("onFailure", t.toString());
}
});
} TabLayout tabLayout = findViewById(R.id.tabs);
Typeface myTypeface;
switch(tinyDb.getInt("customFontId", -1)) {
case 0:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/roboto.ttf");
break;
case 2:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/sourcecodeproregular.ttf");
break;
default:
myTypeface = Typeface.createFromAsset(getApplicationContext().getAssets(), "fonts/manroperegular.ttf");
break;
}
toolbarTitle.setTypeface(myTypeface);
toolbarTitle.setText(repoName1);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for(int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for(int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if(tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
// only show Collaborators if you have permission to
final View collaboratorTab = vg.getChildAt(8);
if(tinyDb.getBoolean("isRepoAdmin")) {
collaboratorTab.setVisibility(View.VISIBLE);
}
else {
collaboratorTab.setVisibility(View.GONE);
}
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
if(tinyDb.getBoolean("enableCounterBadges")) {
@SuppressLint("InflateParams") View tabHeader2 = LayoutInflater.from(this).inflate(R.layout.badge_issue, null);
textViewBadgeIssue = tabHeader2.findViewById(R.id.counterBadgeIssue);
@SuppressLint("InflateParams") View tabHeader4 = LayoutInflater.from(this).inflate(R.layout.badge_pull, null);
textViewBadgePull = tabHeader4.findViewById(R.id.counterBadgePull);
@SuppressLint("InflateParams") View tabHeader6 = LayoutInflater.from(this).inflate(R.layout.badge_release, null);
textViewBadgeRelease = tabHeader6.findViewById(R.id.counterBadgeRelease);
textViewBadgeIssue.setVisibility(View.GONE);
textViewBadgePull.setVisibility(View.GONE);
textViewBadgeRelease.setVisibility(View.GONE);
getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
ColorStateList textColor = tabLayout.getTabTextColors();
// issue count
if(textViewBadgeIssue.getText() != "") {
TabLayout.Tab tabOpenIssues = tabLayout.getTabAt(2);
Objects.requireNonNull(tabLayout.getTabAt(2)).setCustomView(tabHeader2);
assert tabOpenIssues != null;
TextView openIssueTabView = Objects.requireNonNull(tabOpenIssues.getCustomView()).findViewById(R.id.counterBadgeIssueText);
openIssueTabView.setTextColor(textColor);
}
// pull count
if(textViewBadgePull.getText() != "") { // only show if API returned a number
Objects.requireNonNull(tabLayout.getTabAt(3)).setCustomView(tabHeader4);
TabLayout.Tab tabOpenPulls = tabLayout.getTabAt(3);
assert tabOpenPulls != null;
TextView openPullTabView = Objects.requireNonNull(tabOpenPulls.getCustomView()).findViewById(R.id.counterBadgePullText);
openPullTabView.setTextColor(textColor);
}
// release count
if(VersionCheck.compareVersion("1.11.5", tinyDb.getString("giteaVersion")) < 1) {
if(textViewBadgeRelease.getText() != "") { // only show if API returned a number
Objects.requireNonNull(tabLayout.getTabAt(5)).setCustomView(tabHeader6);
TabLayout.Tab tabOpenRelease = tabLayout.getTabAt(5);
assert tabOpenRelease != null;
TextView openReleaseTabView = Objects.requireNonNull(tabOpenRelease.getCustomView()).findViewById(R.id.counterBadgeReleaseText);
openReleaseTabView.setTextColor(textColor);
}
}
}
checkRepositoryStarStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
checkRepositoryWatchStatus(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName1);
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getApplicationContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(tinyDb.getBoolean("enableCounterIssueBadge")) {
getRepoInfo(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.repo_dotted_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch(id) {
case android.R.id.home:
finish();
return true;
case R.id.repoMenu:
BottomSheetRepoFragment bottomSheet = new BottomSheetRepoFragment();
bottomSheet.show(getSupportFragmentManager(), "repoBottomSheet");
return true;
case R.id.filter:
BottomSheetIssuesFilterFragment filterBottomSheet = new BottomSheetIssuesFilterFragment();
filterBottomSheet.show(getSupportFragmentManager(), "repoFilterMenuBottomSheet");
return true;
case R.id.filterPr:
BottomSheetPullRequestFilterFragment filterPrBottomSheet = new BottomSheetPullRequestFilterFragment();
filterPrBottomSheet.show(getSupportFragmentManager(), "repoFilterMenuPrBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onButtonClicked(String text) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String instanceUrlWithProtocol = "https://" + tinyDb.getString("instanceUrlRaw");
if(!tinyDb.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDb.getString("instanceUrlWithProtocol");
}
Uri url = Uri.parse(instanceUrlWithProtocol + "/" + repoFullName);
switch(text) {
case "label":
startActivity(new Intent(RepoDetailActivity.this, CreateLabelActivity.class));
break;
case "newIssue":
startActivity(new Intent(RepoDetailActivity.this, CreateIssueActivity.class));
break;
case "newMilestone":
startActivity(new Intent(RepoDetailActivity.this, CreateMilestoneActivity.class));
break;
case "addCollaborator":
startActivity(new Intent(RepoDetailActivity.this, AddCollaboratorToRepositoryActivity.class));
break;
case "createRelease":
startActivity(new Intent(RepoDetailActivity.this, CreateReleaseActivity.class));
break;
case "openWebRepo":
Intent i = new Intent(Intent.ACTION_VIEW, url);
startActivity(i);
break;
case "shareRepo":
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, url);
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, url);
startActivity(Intent.createChooser(sharingIntent, url.toString()));
break;
case "newFile":
startActivity(new Intent(RepoDetailActivity.this, CreateFileActivity.class));
break;
case "openIssues":
if(getFragmentRefreshListener() != null) {
getFragmentRefreshListener().onRefresh("open");
}
break;
case "closedIssues":
if(getFragmentRefreshListener() != null) {
getFragmentRefreshListener().onRefresh("closed");
}
break;
case "openPr":
if(getFragmentRefreshListenerPr() != null) {
getFragmentRefreshListenerPr().onRefresh("open");
}
break;
case "closedPr":
if(getFragmentRefreshListenerPr() != null) {
getFragmentRefreshListenerPr().onRefresh("closed");
}
break;
}
}
public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
String repoOwner = parts[0];
String repoName = parts[1];
Fragment fragment = null;
switch(position) {
case 0: // information
return RepoInfoFragment.newInstance(repoOwner, repoName);
case 1: // files
return FilesFragment.newInstance(repoOwner, repoName);
case 2: // issues
fragment = new IssuesFragment();
break;
case 3: // pull requests
fragment = new PullRequestsFragment();
break;
case 4: // branches
return BranchesFragment.newInstance(repoOwner, repoName);
case 5: // releases
return ReleasesFragment.newInstance(repoOwner, repoName);
case 6: // milestones
return MilestonesFragment.newInstance(repoOwner, repoName);
case 7: // labels
return LabelsFragment.newInstance(repoOwner, repoName);
case 8: // collaborators
return CollaboratorsFragment.newInstance(repoOwner, repoName);
}
assert fragment != null;
return fragment;
}
@Override
public int getCount() {
return 9;
}
}
private void getRepoInfo(String instanceUrl, String token, final String owner, String repo) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
Call<UserRepositories> call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().getUserRepository(token, owner, repo);
call.enqueue(new Callback<UserRepositories>() {
@Override
public void onResponse(@NonNull Call<UserRepositories> call, @NonNull retrofit2.Response<UserRepositories> response) {
UserRepositories repoInfo = response.body();
if(response.isSuccessful()) {
if(response.code() == 200) {
if(tinyDb.getBoolean("enableCounterBadges")) {
assert repoInfo != null;
if(repoInfo.getOpen_issues_count() != null) {
textViewBadgeIssue.setVisibility(View.VISIBLE);
textViewBadgeIssue.setText(repoInfo.getOpen_issues_count());
}
if(repoInfo.getOpen_pull_count() != null) {
textViewBadgePull.setVisibility(View.VISIBLE);
textViewBadgePull.setText(repoInfo.getOpen_pull_count());
}
if(repoInfo.getRelease_count() != null) {
textViewBadgeRelease.setVisibility(View.VISIBLE);
textViewBadgeRelease.setText(repoInfo.getRelease_count());
}
}
}
}
else {
Log.e("onFailure", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void checkRepositoryStarStatus(String instanceUrl, String instanceToken, final String owner, String repo) {
Call<JsonElement> call;
call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().checkRepoStarStatus(instanceToken, owner, repo);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
tinyDb.putInt("repositoryStarStatus", response.code());
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
private void checkRepositoryWatchStatus(String instanceUrl, String instanceToken, final String owner, String repo) {
Call<WatchRepository> call;
call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().checkRepoWatchStatus(instanceToken, owner, repo);
call.enqueue(new Callback<WatchRepository>() {
@Override
public void onResponse(@NonNull Call<WatchRepository> call, @NonNull retrofit2.Response<WatchRepository> response) {
TinyDB tinyDb = new TinyDB(getApplicationContext());
if(response.code() == 200) {
assert response.body() != null;
if(response.body().getSubscribed()) {
tinyDb.putBoolean("repositoryWatchStatus", true);
}
}
else {
tinyDb.putBoolean("repositoryWatchStatus", false);
}
}
@Override
public void onFailure(@NonNull Call<WatchRepository> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
} }

View File

@ -1,29 +1,28 @@
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;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.mikepenz.fastadapter.FastAdapter;
import com.mikepenz.fastadapter.items.AbstractItem;
import com.mikepenz.fastadapter.listeners.ClickEventHook;
import com.mikepenz.fastadapter.utils.EventHookUtil;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.IssueDetailActivity; import org.mian.gitnex.activities.IssueDetailActivity;
import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.helpers.ClickListener; import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime; import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -31,112 +30,74 @@ import java.util.Locale;
* Author M M Arif * Author M M Arif
*/ */
public class IssuesAdapter extends AbstractItem<IssuesAdapter, IssuesAdapter.ViewHolder> { public class IssuesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final private Context ctx; private Context context;
private String issueTitle; private final int TYPE_LOAD = 0;
private int issueNumber; private List<Issues> issuesList;
private String issueAssigneeAvatar; private OnLoadMoreListener loadMoreListener;
private Date issueCreatedTime; private boolean isLoading = false, isMoreDataAvailable = true;
private int issueCommentsCount;
private String userFullname;
private String userLogin;
private boolean isSelectable = true; public IssuesAdapter(Context context, List<Issues> issuesListMain) {
public IssuesAdapter(Context ctx) { this.context = context;
this.ctx = ctx; this.issuesList = issuesListMain;
}
public IssuesAdapter withNewItems(String issueTitle, int issueNumber, String issueAssigneeAvatar, Date issueCreatedTime, int issueCommentsCount, String userFullname, String userLogin) {
this.setNewItems(issueTitle, issueNumber, issueAssigneeAvatar, issueCreatedTime, issueCommentsCount, userFullname, userLogin);
return this;
}
private void setNewItems(String issueTitle, int issueNumber, String issueAssigneeAvatar, Date issueCreatedTime, int issueCommentsCount, String userFullname, String userLogin) {
this.issueTitle = issueTitle;
this.issueNumber = issueNumber;
this.issueAssigneeAvatar = issueAssigneeAvatar;
this.issueCreatedTime = issueCreatedTime;
this.issueCommentsCount = issueCommentsCount;
this.userFullname = userFullname;
this.userLogin = userLogin;
}
private int getIssueNumber() {
return issueNumber;
}
public String getIssueTitle() {
return issueTitle;
}
private String getIssueAssigneeAvatar() {
return issueAssigneeAvatar;
}
private Date getIssueCreatedTime() {
return issueCreatedTime;
}
private int getIssueCommentsCount() {
return issueCommentsCount;
}
private String getUserFullname() {
return userFullname;
}
private String getUserLogin() {
return userLogin;
}
@Override
public boolean isEnabled() {
return true;
}
@Override
public IssuesAdapter withEnabled(boolean enabled) {
return null;
}
@Override
public boolean isSelectable() {
return isSelectable;
}
@Override
public IssuesAdapter withSelectable(boolean selectable) {
this.isSelectable = selectable;
return this;
}
@Override
public int getType() {
return R.id.relativeLayoutFrameIssuesList;
}
@Override
public int getLayoutRes() {
return R.layout.list_issues;
} }
@NonNull @NonNull
@Override @Override
public IssuesAdapter.ViewHolder getViewHolder(@NonNull View v) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new IssuesAdapter.ViewHolder(v);
LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD) {
return new IssuesHolder(inflater.inflate(R.layout.list_issues, parent, false));
}
else {
return new LoadHolder(inflater.inflate(R.layout.row_load, parent, false));
}
} }
public class ViewHolder extends FastAdapter.ViewHolder<IssuesAdapter> { @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
final TinyDB tinyDb = new TinyDB(ctx); if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat"); isLoading = true;
loadMoreListener.onLoadMore();
}
if(getItemViewType(position) == TYPE_LOAD) {
((IssuesHolder) holder).bindData(issuesList.get(position));
}
}
@Override
public int getItemViewType(int position) {
if(issuesList.get(position).getTitle() != null) {
return TYPE_LOAD;
}
else {
return 1;
}
}
@Override
public int getItemCount() {
return issuesList.size();
}
class IssuesHolder extends RecyclerView.ViewHolder {
private TextView issueNumber; private TextView issueNumber;
private ImageView issueAssigneeAvatar; private ImageView issueAssigneeAvatar;
@ -144,7 +105,7 @@ public class IssuesAdapter extends AbstractItem<IssuesAdapter, IssuesAdapter.Vie
private TextView issueCreatedTime; private TextView issueCreatedTime;
private TextView issueCommentsCount; private TextView issueCommentsCount;
public ViewHolder(View itemView) { IssuesHolder(View itemView) {
super(itemView); super(itemView);
@ -152,94 +113,124 @@ public class IssuesAdapter extends AbstractItem<IssuesAdapter, IssuesAdapter.Vie
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);
LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount);
issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime); issueCreatedTime = itemView.findViewById(R.id.issueCreatedTime);
issueTitle.setOnClickListener(v -> {
Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
tinyDb.putString("issueType", "issue");
context.startActivity(intent);
});
frameCommentsCount.setOnClickListener(v -> {
Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
tinyDb.putString("issueType", "issue");
context.startActivity(intent);
});
} }
@Override @SuppressLint("SetTextI18n")
public void bindView(@NonNull IssuesAdapter item, @NonNull List<Object> payloads) { void bindData(Issues issuesModel) {
if (!item.getUserFullname().equals("")) { final TinyDB tinyDb = new TinyDB(context);
issueAssigneeAvatar.setOnClickListener(new ClickListener(ctx.getResources().getString(R.string.issueCreator) + item.getUserFullname(), ctx)); final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat");
if(!issuesModel.getUser().getFull_name().equals("")) {
issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getFull_name(), context));
} }
else { else {
issueAssigneeAvatar.setOnClickListener(new ClickListener(ctx.getResources().getString(R.string.issueCreator) + item.getUserLogin(), ctx)); issueAssigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.issueCreator) + issuesModel.getUser().getLogin(), context));
} }
PicassoService.getInstance(ctx).get().load(item.getIssueAssigneeAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar); PicassoService.getInstance(context).get().load(issuesModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(issueAssigneeAvatar);
String issueNumber_ = "<font color='" + ctx.getResources().getColor(R.color.lightGray) + "'>" + ctx.getResources().getString(R.string.hash) + item.getIssueNumber() + "</font>"; String issueNumber_ = "<font color='" + context.getResources().getColor(R.color.lightGray) + "'>" + context.getResources().getString(R.string.hash) + issuesModel.getNumber() + "</font>";
issueTitle.setText(Html.fromHtml(issueNumber_ + " " + item.getIssueTitle())); issueTitle.setText(Html.fromHtml(issueNumber_ + " " + issuesModel.getTitle()));
issueNumber.setText(String.valueOf(item.getIssueNumber())); issueNumber.setText(String.valueOf(issuesModel.getNumber()));
issueCommentsCount.setText(String.valueOf(item.getIssueCommentsCount())); issueCommentsCount.setText(String.valueOf(issuesModel.getComments()));
switch (timeFormat) {
switch(timeFormat) {
case "pretty": { case "pretty": {
PrettyTime prettyTime = new PrettyTime(new Locale(locale)); PrettyTime prettyTime = new PrettyTime(new Locale(locale));
String createdTime = prettyTime.format(item.getIssueCreatedTime()); String createdTime = prettyTime.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime); issueCreatedTime.setText(createdTime);
issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(item.getIssueCreatedTime()), ctx)); issueCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(issuesModel.getCreated_at()), context));
break; break;
} }
case "normal": { case "normal": {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + ctx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale)); DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(item.getIssueCreatedTime()); String createdTime = formatter.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime); issueCreatedTime.setText(createdTime);
break; break;
} }
case "normal1": { case "normal1": {
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + ctx.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale)); DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy '" + context.getResources().getString(R.string.timeAtText) + "' HH:mm", new Locale(locale));
String createdTime = formatter.format(item.getIssueCreatedTime()); String createdTime = formatter.format(issuesModel.getCreated_at());
issueCreatedTime.setText(createdTime); issueCreatedTime.setText(createdTime);
break; break;
} }
} }
} }
@Override
public void unbindView(@NonNull IssuesAdapter item) {
issueTitle.setText(null);
issueCommentsCount.setText(null);
issueCreatedTime.setText(null);
}
} }
public static class IssueTitleClickEvent extends ClickEventHook<IssuesAdapter> { static class LoadHolder extends RecyclerView.ViewHolder {
@Nullable LoadHolder(View itemView) {
@Override
public List<View> onBindMany(@NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof IssuesAdapter.ViewHolder) {
return EventHookUtil.toList(((ViewHolder) viewHolder).issueTitle);
}
return super.onBindMany(viewHolder);
super(itemView);
} }
@Override }
public void onClick(View v, int position, @NonNull FastAdapter<IssuesAdapter> fastAdapter, IssuesAdapter item) {
Context context = v.getContext(); public void setMoreDataAvailable(boolean moreDataAvailable) {
Intent intent = new Intent(context, IssueDetailActivity.class); isMoreDataAvailable = moreDataAvailable;
intent.putExtra("issueNumber", item.getIssueNumber());
TinyDB tinyDb = new TinyDB(context); }
tinyDb.putString("issueNumber", String.valueOf(item.getIssueNumber()));
tinyDb.putString("issueType", "issue");
context.startActivity(intent);
} public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
}
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}
public void updateList(List<Issues> list) {
issuesList = list;
notifyDataSetChanged();
} }
} }

View File

@ -7,8 +7,6 @@ import android.text.Html;
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.Filter;
import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
@ -22,10 +20,6 @@ import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.models.PullRequests; import org.mian.gitnex.models.PullRequests;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -33,231 +27,196 @@ import java.util.Locale;
* Author M M Arif * Author M M Arif
*/ */
public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable { public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context; private Context context;
private final int TYPE_LOAD = 0; private final int TYPE_LOAD = 0;
private List<PullRequests> prList; private List<PullRequests> prList;
private List<PullRequests> prListFull; private PullRequestsAdapter.OnLoadMoreListener loadMoreListener;
private PullRequestsAdapter.OnLoadMoreListener loadMoreListener; private boolean isLoading = false, isMoreDataAvailable = true;
private boolean isLoading = false, isMoreDataAvailable = true;
public PullRequestsAdapter(Context context, List<PullRequests> prListMain) { public PullRequestsAdapter(Context context, List<PullRequests> prListMain) {
this.context = context; this.context = context;
this.prList = prListMain; this.prList = prListMain;
prListFull = new ArrayList<>(prList);
} }
@NonNull @NonNull
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context); LayoutInflater inflater = LayoutInflater.from(context);
if(viewType == TYPE_LOAD){ if(viewType == TYPE_LOAD) {
return new PullRequestsAdapter.PullRequestsHolder(inflater.inflate(R.layout.list_pr, parent,false)); return new PullRequestsAdapter.PullRequestsHolder(inflater.inflate(R.layout.list_pr, parent, false));
} }
else { else {
return new PullRequestsAdapter.LoadHolder(inflater.inflate(R.layout.row_load,parent,false)); return new PullRequestsAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false));
} }
} }
@Override @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(position >= getItemCount()-1 && isMoreDataAvailable && !isLoading && loadMoreListener!=null) { if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
isLoading = true; isLoading = true;
loadMoreListener.onLoadMore(); loadMoreListener.onLoadMore();
} }
if(getItemViewType(position) == TYPE_LOAD) { if(getItemViewType(position) == TYPE_LOAD) {
((PullRequestsAdapter.PullRequestsHolder)holder).bindData(prList.get(position)); ((PullRequestsAdapter.PullRequestsHolder) holder).bindData(prList.get(position));
} }
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if(prList.get(position).getTitle() != null) { if(prList.get(position).getTitle() != null) {
return TYPE_LOAD; return TYPE_LOAD;
} }
else { else {
return 1; return 1;
} }
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return prList.size(); return prList.size();
} }
class PullRequestsHolder extends RecyclerView.ViewHolder { class PullRequestsHolder extends RecyclerView.ViewHolder {
private TextView prNumber; private TextView prNumber;
private ImageView assigneeAvatar; private ImageView assigneeAvatar;
private TextView prTitle; private TextView prTitle;
private TextView prCreatedTime; private TextView prCreatedTime;
private TextView prCommentsCount; private TextView prCommentsCount;
PullRequestsHolder(View itemView) { PullRequestsHolder(View itemView) {
super(itemView); super(itemView);
prNumber = itemView.findViewById(R.id.prNumber); prNumber = itemView.findViewById(R.id.prNumber);
assigneeAvatar = itemView.findViewById(R.id.assigneeAvatar); assigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
prTitle = itemView.findViewById(R.id.prTitle); prTitle = itemView.findViewById(R.id.prTitle);
prCommentsCount = itemView.findViewById(R.id.prCommentsCount); prCommentsCount = itemView.findViewById(R.id.prCommentsCount);
LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount); LinearLayout frameCommentsCount = itemView.findViewById(R.id.frameCommentsCount);
prCreatedTime = itemView.findViewById(R.id.prCreatedTime); prCreatedTime = itemView.findViewById(R.id.prCreatedTime);
prTitle.setOnClickListener(new View.OnClickListener() { prTitle.setOnClickListener(v -> {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class); Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText()); intent.putExtra("issueNumber", prNumber.getText());
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", prNumber.getText().toString()); tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("issueType", "pr"); tinyDb.putString("issueType", "pr");
context.startActivity(intent); context.startActivity(intent);
} });
}); frameCommentsCount.setOnClickListener(v -> {
frameCommentsCount.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext(); Context context = v.getContext();
Intent intent = new Intent(context, IssueDetailActivity.class); Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText()); intent.putExtra("issueNumber", prNumber.getText());
TinyDB tinyDb = new TinyDB(context); TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", prNumber.getText().toString()); tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("issueType", "pr"); tinyDb.putString("issueType", "pr");
context.startActivity(intent); context.startActivity(intent);
} });
});
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
void bindData(PullRequests prModel){ void bindData(PullRequests prModel) {
final TinyDB tinyDb = new TinyDB(context); final TinyDB tinyDb = new TinyDB(context);
final String locale = tinyDb.getString("locale"); final String locale = tinyDb.getString("locale");
final String timeFormat = tinyDb.getString("dateFormat"); final String timeFormat = tinyDb.getString("dateFormat");
if (!prModel.getUser().getFull_name().equals("")) { if(!prModel.getUser().getFull_name().equals("")) {
assigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.prCreator) + prModel.getUser().getFull_name(), context)); assigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.prCreator) + prModel.getUser().getFull_name(), context));
} else { }
assigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.prCreator) + prModel.getUser().getLogin(), context)); else {
} assigneeAvatar.setOnClickListener(new ClickListener(context.getResources().getString(R.string.prCreator) + prModel.getUser().getLogin(), context));
}
if (prModel.getUser().getAvatar_url() != null) { if(prModel.getUser().getAvatar_url() != null) {
PicassoService.getInstance(context).get().load(prModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar); PicassoService.getInstance(context).get().load(prModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar);
} else { }
PicassoService.getInstance(context).get().load(prModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar); else {
} PicassoService.getInstance(context).get().load(prModel.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(assigneeAvatar);
}
String prNumber_ = "<font color='" + context.getResources().getColor(R.color.lightGray) + "'>" + context.getResources().getString(R.string.hash) + prModel.getNumber() + "</font>"; String prNumber_ = "<font color='" + context.getResources().getColor(R.color.lightGray) + "'>" + context.getResources().getString(R.string.hash) + prModel.getNumber() + "</font>";
prTitle.setText(Html.fromHtml(prNumber_ + " " + prModel.getTitle())); prTitle.setText(Html.fromHtml(prNumber_ + " " + prModel.getTitle()));
prNumber.setText(String.valueOf(prModel.getNumber())); prNumber.setText(String.valueOf(prModel.getNumber()));
prCommentsCount.setText(String.valueOf(prModel.getComments())); prCommentsCount.setText(String.valueOf(prModel.getComments()));
prCreatedTime.setText(TimeHelper.formatTime(prModel.getCreated_at(), new Locale(locale), timeFormat, context)); prCreatedTime.setText(TimeHelper.formatTime(prModel.getCreated_at(), new Locale(locale), timeFormat, context));
if(timeFormat.equals("pretty")) { if(timeFormat.equals("pretty")) {
prCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(prModel.getCreated_at()), context)); prCreatedTime.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(prModel.getCreated_at()), context));
} }
} }
} }
static class LoadHolder extends RecyclerView.ViewHolder { static class LoadHolder extends RecyclerView.ViewHolder {
LoadHolder(View itemView) { LoadHolder(View itemView) {
super(itemView);
}
} super(itemView);
}
public void setMoreDataAvailable(boolean moreDataAvailable) { }
isMoreDataAvailable = moreDataAvailable; public void setMoreDataAvailable(boolean moreDataAvailable) {
} isMoreDataAvailable = moreDataAvailable;
public void notifyDataChanged() { }
notifyDataSetChanged(); public void notifyDataChanged() {
isLoading = false;
} notifyDataSetChanged();
isLoading = false;
public interface OnLoadMoreListener { }
void onLoadMore(); public interface OnLoadMoreListener {
} void onLoadMore();
public void setLoadMoreListener(PullRequestsAdapter.OnLoadMoreListener loadMoreListener) { }
this.loadMoreListener = loadMoreListener; public void setLoadMoreListener(PullRequestsAdapter.OnLoadMoreListener loadMoreListener) {
} this.loadMoreListener = loadMoreListener;
@Override }
public Filter getFilter() {
return prFilter;
}
private Filter prFilter = new Filter() { public void updateList(List<PullRequests> list) {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<PullRequests> filteredList = new ArrayList<>();
if (constraint == null || constraint.length() == 0) { prList = list;
filteredList.addAll(prList); notifyDataSetChanged();
} else { }
String filterPattern = constraint.toString().toLowerCase().trim();
for (PullRequests item : prList) {
if (item.getTitle().toLowerCase().contains(filterPattern) || item.getBody().toLowerCase().contains(filterPattern)) {
filteredList.add(item);
}
}
}
FilterResults results = new FilterResults();
results.values = filteredList;
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
prList.clear();
prList.addAll((List) results.values);
notifyDataSetChanged();
}
};
} }

View File

@ -0,0 +1,63 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R;
/**
* Author M M Arif
*/
public class BottomSheetIssuesFilterFragment extends BottomSheetDialogFragment {
private BottomSheetIssuesFilterFragment.BottomSheetListener bmListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.bottom_sheet_issues_filter, container, false);
TextView openIssues = v.findViewById(R.id.openIssues);
TextView closedIssues = v.findViewById(R.id.closedIssues);
openIssues.setOnClickListener(v1 -> {
bmListener.onButtonClicked("openIssues");
dismiss();
});
closedIssues.setOnClickListener(v12 -> {
bmListener.onButtonClicked("closedIssues");
dismiss();
});
return v;
}
public interface BottomSheetListener {
void onButtonClicked(String text);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
bmListener = (BottomSheetIssuesFilterFragment.BottomSheetListener) context;
}
catch(ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement BottomSheetListener");
}
}
}

View File

@ -0,0 +1,63 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R;
/**
* Author M M Arif
*/
public class BottomSheetPullRequestFilterFragment extends BottomSheetDialogFragment {
private BottomSheetPullRequestFilterFragment.BottomSheetListener bmListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.bottom_sheet_pull_request_filter, container, false);
TextView openPr = v.findViewById(R.id.openPr);
TextView closedPr = v.findViewById(R.id.closedPr);
openPr.setOnClickListener(v1 -> {
bmListener.onButtonClicked("openPr");
dismiss();
});
closedPr.setOnClickListener(v12 -> {
bmListener.onButtonClicked("closedPr");
dismiss();
});
return v;
}
public interface BottomSheetListener {
void onButtonClicked(String text);
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
bmListener = (BottomSheetPullRequestFilterFragment.BottomSheetListener) context;
}
catch(ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement BottomSheetListener");
}
}
}

View File

@ -1,5 +1,7 @@
package org.mian.gitnex.fragments; package org.mian.gitnex.fragments;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@ -7,6 +9,8 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.actions.IssueActions; import org.mian.gitnex.actions.IssueActions;
@ -17,10 +21,6 @@ import org.mian.gitnex.activities.FileDiffActivity;
import org.mian.gitnex.activities.MergePullRequestActivity; import org.mian.gitnex.activities.MergePullRequestActivity;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.content.ClipboardManager;
import android.content.ClipData;
import java.util.Objects; import java.util.Objects;
/** /**
@ -29,213 +29,219 @@ import java.util.Objects;
public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment { public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
@Nullable @Nullable
@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) {
View v = inflater.inflate(R.layout.bottom_sheet_single_issue_layout, container, false); View v = inflater.inflate(R.layout.bottom_sheet_single_issue_layout, container, false);
final Context ctx = getContext(); final Context ctx = getContext();
final TinyDB tinyDB = new TinyDB(ctx); final TinyDB tinyDB = new TinyDB(ctx);
TextView editIssue = v.findViewById(R.id.editIssue); TextView editIssue = v.findViewById(R.id.editIssue);
TextView editLabels = v.findViewById(R.id.editLabels); TextView editLabels = v.findViewById(R.id.editLabels);
TextView closeIssue = v.findViewById(R.id.closeIssue); TextView closeIssue = v.findViewById(R.id.closeIssue);
TextView reOpenIssue = v.findViewById(R.id.reOpenIssue); TextView reOpenIssue = v.findViewById(R.id.reOpenIssue);
TextView addRemoveAssignees = v.findViewById(R.id.addRemoveAssignees); TextView addRemoveAssignees = v.findViewById(R.id.addRemoveAssignees);
TextView copyIssueUrl = v.findViewById(R.id.copyIssueUrl); TextView copyIssueUrl = v.findViewById(R.id.copyIssueUrl);
TextView openFilesDiff = v.findViewById(R.id.openFilesDiff); TextView openFilesDiff = v.findViewById(R.id.openFilesDiff);
TextView mergePullRequest = v.findViewById(R.id.mergePullRequest); TextView mergePullRequest = v.findViewById(R.id.mergePullRequest);
TextView shareIssue = v.findViewById(R.id.shareIssue); TextView shareIssue = v.findViewById(R.id.shareIssue);
TextView subscribeIssue = v.findViewById(R.id.subscribeIssue); TextView subscribeIssue = v.findViewById(R.id.subscribeIssue);
TextView unsubscribeIssue = v.findViewById(R.id.unsubscribeIssue); TextView unsubscribeIssue = v.findViewById(R.id.unsubscribeIssue);
if(tinyDB.getString("issueType").equals("pr")) { if(tinyDB.getString("issueType").equals("pr")) {
editIssue.setText(R.string.editPrText); editIssue.setText(R.string.editPrText);
copyIssueUrl.setText(R.string.copyPrUrlText); copyIssueUrl.setText(R.string.copyPrUrlText);
shareIssue.setText(R.string.sharePr); shareIssue.setText(R.string.sharePr);
if(tinyDB.getBoolean("prMerged")) { if(tinyDB.getBoolean("prMerged") || tinyDB.getString("repoPrState").equals("closed")) {
mergePullRequest.setVisibility(View.GONE); mergePullRequest.setVisibility(View.GONE);
} }
else { else {
mergePullRequest.setVisibility(View.VISIBLE); mergePullRequest.setVisibility(View.VISIBLE);
} }
if(tinyDB.getString("repoType").equals("public")) { if(tinyDB.getString("repoType").equals("public")) {
openFilesDiff.setVisibility(View.VISIBLE); openFilesDiff.setVisibility(View.VISIBLE);
} }
else { else {
openFilesDiff.setVisibility(View.GONE); openFilesDiff.setVisibility(View.GONE);
} }
} }
else { else {
mergePullRequest.setVisibility(View.GONE); mergePullRequest.setVisibility(View.GONE);
} }
mergePullRequest.setOnClickListener(new View.OnClickListener() { mergePullRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(ctx, MergePullRequestActivity.class)); @Override
dismiss(); public void onClick(View v) {
} startActivity(new Intent(ctx, MergePullRequestActivity.class));
}); dismiss();
openFilesDiff.setOnClickListener(new View.OnClickListener() { }
@Override });
public void onClick(View v) {
startActivity(new Intent(ctx, FileDiffActivity.class)); openFilesDiff.setOnClickListener(new View.OnClickListener() {
dismiss();
} @Override
}); public void onClick(View v) {
editIssue.setOnClickListener(new View.OnClickListener() { startActivity(new Intent(ctx, FileDiffActivity.class));
@Override dismiss();
public void onClick(View v) {
startActivity(new Intent(ctx, EditIssueActivity.class)); }
dismiss(); });
} editIssue.setOnClickListener(new View.OnClickListener() {
});
editLabels.setOnClickListener(new View.OnClickListener() { @Override
@Override public void onClick(View v) {
public void onClick(View v) {
startActivity(new Intent(ctx, AddRemoveLabelsActivity.class)); startActivity(new Intent(ctx, EditIssueActivity.class));
dismiss(); dismiss();
} }
}); });
addRemoveAssignees.setOnClickListener(new View.OnClickListener() { editLabels.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(ctx, AddRemoveAssigneesActivity.class)); @Override
dismiss(); public void onClick(View v) {
} startActivity(new Intent(ctx, AddRemoveLabelsActivity.class));
}); dismiss();
shareIssue.setOnClickListener(v1 -> { }
});
// get url of repo addRemoveAssignees.setOnClickListener(new View.OnClickListener() {
String repoFullName = tinyDB.getString("repoFullName");
String instanceUrlWithProtocol = "https://" + tinyDB.getString("instanceUrlRaw");
if (!tinyDB.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDB.getString("instanceUrlWithProtocol");
}
// get issue Url @Override
String issueUrl = instanceUrlWithProtocol + "/" + repoFullName + "/issues/" + tinyDB.getString("issueNumber"); public void onClick(View v) {
// share issue startActivity(new Intent(ctx, AddRemoveAssigneesActivity.class));
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); dismiss();
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.hash) + tinyDB.getString("issueNumber") + " " + tinyDB.getString("issueTitle"));
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, issueUrl);
startActivity(Intent.createChooser(sharingIntent, getResources().getString(R.string.hash) + tinyDB.getString("issueNumber") + " " + tinyDB.getString("issueTitle")));
dismiss(); }
});
}); shareIssue.setOnClickListener(v1 -> {
copyIssueUrl.setOnClickListener(new View.OnClickListener() { // get url of repo
@Override String repoFullName = tinyDB.getString("repoFullName");
public void onClick(View v) { String instanceUrlWithProtocol = "https://" + tinyDB.getString("instanceUrlRaw");
if(!tinyDB.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDB.getString("instanceUrlWithProtocol");
}
// get url of repo // get issue Url
String repoFullName = tinyDB.getString("repoFullName"); String issueUrl = instanceUrlWithProtocol + "/" + repoFullName + "/issues/" + tinyDB.getString("issueNumber");
String instanceUrlWithProtocol = "https://" + tinyDB.getString("instanceUrlRaw");
if (!tinyDB.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDB.getString("instanceUrlWithProtocol");
}
// get issue Url // share issue
String issueUrl = instanceUrlWithProtocol + "/" + repoFullName + "/issues/" + tinyDB.getString("issueNumber"); Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, getResources().getString(R.string.hash) + tinyDB.getString("issueNumber") + " " + tinyDB.getString("issueTitle"));
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, issueUrl);
startActivity(Intent.createChooser(sharingIntent, getResources().getString(R.string.hash) + tinyDB.getString("issueNumber") + " " + tinyDB.getString("issueTitle")));
// copy to clipboard dismiss();
ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(ctx).getSystemService(android.content.Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("issueUrl", issueUrl);
assert clipboard != null;
clipboard.setPrimaryClip(clip);
dismiss(); });
Toasty.info(ctx, ctx.getString(R.string.copyIssueUrlToastMsg)); copyIssueUrl.setOnClickListener(new View.OnClickListener() {
} @Override
}); public void onClick(View v) {
if(tinyDB.getString("issueType").equals("issue")) { // get url of repo
String repoFullName = tinyDB.getString("repoFullName");
String instanceUrlWithProtocol = "https://" + tinyDB.getString("instanceUrlRaw");
if(!tinyDB.getString("instanceUrlWithProtocol").isEmpty()) {
instanceUrlWithProtocol = tinyDB.getString("instanceUrlWithProtocol");
}
if (tinyDB.getString("issueState").equals("open")) { // close issue // get issue Url
String issueUrl = instanceUrlWithProtocol + "/" + repoFullName + "/issues/" + tinyDB.getString("issueNumber");
reOpenIssue.setVisibility(View.GONE); // copy to clipboard
closeIssue.setVisibility(View.VISIBLE); ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(ctx).getSystemService(android.content.Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("issueUrl", issueUrl);
assert clipboard != null;
clipboard.setPrimaryClip(clip);
closeIssue.setOnClickListener(closeSingleIssue -> { dismiss();
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "closed"); Toasty.info(ctx, ctx.getString(R.string.copyIssueUrlToastMsg));
dismiss();
}); }
});
} if(tinyDB.getString("issueType").equals("issue")) {
else if (tinyDB.getString("issueState").equals("closed")) {
closeIssue.setVisibility(View.GONE); if(tinyDB.getString("issueState").equals("open")) { // close issue
reOpenIssue.setVisibility(View.VISIBLE);
reOpenIssue.setOnClickListener(reOpenSingleIssue -> { reOpenIssue.setVisibility(View.GONE);
closeIssue.setVisibility(View.VISIBLE);
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "open"); closeIssue.setOnClickListener(closeSingleIssue -> {
dismiss();
}); IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "closed");
dismiss();
} });
} }
else { else if(tinyDB.getString("issueState").equals("closed")) {
reOpenIssue.setVisibility(View.GONE); closeIssue.setVisibility(View.GONE);
closeIssue.setVisibility(View.GONE); reOpenIssue.setVisibility(View.VISIBLE);
} reOpenIssue.setOnClickListener(reOpenSingleIssue -> {
subscribeIssue.setOnClickListener(subscribeToIssue -> { IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "open");
dismiss();
IssueActions.subscribe(ctx, subscribeIssue, unsubscribeIssue); });
//dismiss();
}); }
unsubscribeIssue.setOnClickListener(unsubscribeToIssue -> { }
else {
IssueActions.unsubscribe(ctx, subscribeIssue, unsubscribeIssue); reOpenIssue.setVisibility(View.GONE);
//dismiss(); closeIssue.setVisibility(View.GONE);
}); }
//if RepoWatch True Provide Unsubscribe first subscribeIssue.setOnClickListener(subscribeToIssue -> {
// ToDo: API to check if user is subscribed to an issue (do not exist can be guessed by many api endpoints :/)
if (tinyDB.getBoolean("repoWatch")) {
subscribeIssue.setVisibility(View.GONE);
unsubscribeIssue.setVisibility(View.VISIBLE);
}
return v; IssueActions.subscribe(ctx, subscribeIssue, unsubscribeIssue);
} //dismiss();
});
unsubscribeIssue.setOnClickListener(unsubscribeToIssue -> {
IssueActions.unsubscribe(ctx, subscribeIssue, unsubscribeIssue);
//dismiss();
});
//if RepoWatch True Provide Unsubscribe first
// ToDo: API to check if user is subscribed to an issue (do not exist can be guessed by many api endpoints :/)
if(tinyDB.getBoolean("repoWatch")) {
subscribeIssue.setVisibility(View.GONE);
unsubscribeIssue.setVisibility(View.VISIBLE);
}
return v;
}
} }

View File

@ -4,14 +4,6 @@ import android.annotation.SuppressLint;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@ -22,12 +14,19 @@ import android.view.inputmethod.EditorInfo;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.FileViewActivity; import org.mian.gitnex.activities.FileViewActivity;
import org.mian.gitnex.adapters.FilesAdapter; import org.mian.gitnex.adapters.FilesAdapter;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.models.Files; import org.mian.gitnex.models.Files;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.FilesViewModel; import org.mian.gitnex.viewmodels.FilesViewModel;
import java.util.ArrayList; import java.util.ArrayList;
@ -44,268 +43,275 @@ import moe.feng.common.view.breadcrumbs.model.BreadcrumbItem;
public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapterListener { public class FilesFragment extends Fragment implements FilesAdapter.FilesAdapterListener {
private ProgressBar mProgressBar; private ProgressBar mProgressBar;
private FilesAdapter adapter; private FilesAdapter adapter;
private RecyclerView mRecyclerView; private RecyclerView mRecyclerView;
private TextView noDataFiles; private TextView noDataFiles;
private LinearLayout filesFrame; private LinearLayout filesFrame;
private TextView fileStructure; private TextView fileStructure;
private static String repoNameF = "param2"; private static String repoNameF = "param2";
private static String repoOwnerF = "param1"; private static String repoOwnerF = "param1";
private BreadcrumbsView mBreadcrumbsView; private BreadcrumbsView mBreadcrumbsView;
private String repoName; private String repoName;
private String repoOwner; private String repoOwner;
private OnFragmentInteractionListener mListener; private OnFragmentInteractionListener mListener;
public FilesFragment() { public FilesFragment() {
}
public static FilesFragment newInstance(String param1, String param2) { }
FilesFragment fragment = new FilesFragment();
Bundle args = new Bundle();
args.putString(repoOwnerF, param1);
args.putString(repoNameF, param2);
fragment.setArguments(args);
return fragment;
}
@Override public static FilesFragment newInstance(String param1, String param2) {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
repoName = getArguments().getString(repoNameF);
repoOwner = getArguments().getString(repoOwnerF);
}
}
@Override FilesFragment fragment = new FilesFragment();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle args = new Bundle();
Bundle savedInstanceState) { args.putString(repoOwnerF, param1);
args.putString(repoNameF, param2);
fragment.setArguments(args);
return fragment;
}
View v = inflater.inflate(R.layout.fragment_files, container, false); @Override
setHasOptionsMenu(true); public void onCreate(Bundle savedInstanceState) {
TinyDB tinyDb = new TinyDB(getContext()); super.onCreate(savedInstanceState);
final String instanceUrl = tinyDb.getString("instanceUrl"); if(getArguments() != null) {
final String loginUid = tinyDb.getString("loginUid"); repoName = getArguments().getString(repoNameF);
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); repoOwner = getArguments().getString(repoOwnerF);
}
}
noDataFiles = v.findViewById(R.id.noDataFiles); @Override
filesFrame = v.findViewById(R.id.filesFrame); public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
fileStructure = v.findViewById(R.id.fileStructure); View v = inflater.inflate(R.layout.fragment_files, container, false);
mRecyclerView = v.findViewById(R.id.recyclerView); setHasOptionsMenu(true);
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), TinyDB tinyDb = new TinyDB(getContext());
DividerItemDecoration.VERTICAL); final String instanceUrl = tinyDb.getString("instanceUrl");
mRecyclerView.addItemDecoration(dividerItemDecoration); final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
mProgressBar = v.findViewById(R.id.progress_bar); noDataFiles = v.findViewById(R.id.noDataFiles);
filesFrame = v.findViewById(R.id.filesFrame);
mBreadcrumbsView = v.findViewById(R.id.breadcrumbs_view); fileStructure = v.findViewById(R.id.fileStructure);
mBreadcrumbsView.setItems(new ArrayList<>(Arrays.asList( mRecyclerView = v.findViewById(R.id.recyclerView);
BreadcrumbItem.createSimpleItem(getResources().getString(R.string.filesBreadcrumbRoot)) mRecyclerView.setHasFixedSize(true);
))); mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
return v; mProgressBar = v.findViewById(R.id.progress_bar);
}
@Override mBreadcrumbsView = v.findViewById(R.id.breadcrumbs_view);
public void onResume() { mBreadcrumbsView.setItems(new ArrayList<>(Arrays.asList(BreadcrumbItem.createSimpleItem(getResources().getString(R.string.filesBreadcrumbRoot)))));
super.onResume();
}
private static BreadcrumbItem createItem(String title) { fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
List<String> list = new ArrayList<>();
list.add(title);
return new BreadcrumbItem(list);
}
@Override return v;
public void onClickDir(String dirName) { }
TinyDB tinyDb = new TinyDB(getContext()); @Override
final String instanceUrl = tinyDb.getString("instanceUrl"); public void onResume() {
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
StringBuilder breadcrumbBuilder = new StringBuilder(); super.onResume();
}
breadcrumbBuilder.append(fileStructure.getText().toString()).append("/").append(dirName); private static BreadcrumbItem createItem(String title) {
fileStructure.setText(breadcrumbBuilder); List<String> list = new ArrayList<>();
list.add(title);
return new BreadcrumbItem(list);
}
String dirName_ = fileStructure.getText().toString(); @Override
dirName_ = dirName_.startsWith("/") ? dirName_.substring(1) : dirName_; public void onClickDir(String dirName) {
final String finalDirName_ = dirName_;
mBreadcrumbsView.addItem(createItem(dirName)); TinyDB tinyDb = new TinyDB(getContext());
//noinspection unchecked final String instanceUrl = tinyDb.getString("instanceUrl");
mBreadcrumbsView.setCallback(new DefaultBreadcrumbsCallback<BreadcrumbItem>() { final String loginUid = tinyDb.getString("loginUid");
@SuppressLint("SetTextI18n") final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
@Override
public void onNavigateBack(BreadcrumbItem item, int position) {
if(position == 0) { StringBuilder breadcrumbBuilder = new StringBuilder();
fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
fileStructure.setText("");
return;
}
String filterDir = fileStructure.getText().toString(); breadcrumbBuilder.append(fileStructure.getText().toString()).append("/").append(dirName);
String result = filterDir.substring(0, filterDir.indexOf(item.getSelectedItem()));
fileStructure.setText(result + item.getSelectedItem());
String currentIndex = (result + item.getSelectedItem()).substring(1); fileStructure.setText(breadcrumbBuilder);
fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, currentIndex); String dirName_ = fileStructure.getText().toString();
dirName_ = dirName_.startsWith("/") ? dirName_.substring(1) : dirName_;
final String finalDirName_ = dirName_;
} mBreadcrumbsView.addItem(createItem(dirName));
//noinspection unchecked
mBreadcrumbsView.setCallback(new DefaultBreadcrumbsCallback<BreadcrumbItem>() {
@Override @SuppressLint("SetTextI18n")
public void onNavigateNewLocation(BreadcrumbItem newItem, int changedPosition) { @Override
public void onNavigateBack(BreadcrumbItem item, int position) {
} if(position == 0) {
}); fetchDataAsync(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName);
fileStructure.setText("");
return;
}
fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, finalDirName_); String filterDir = fileStructure.getText().toString();
String result = filterDir.substring(0, filterDir.indexOf(item.getSelectedItem()));
fileStructure.setText(result + item.getSelectedItem());
} String currentIndex = (result + item.getSelectedItem()).substring(1);
@Override fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, currentIndex);
public void onClickFile(String fileName) {
Intent intent = new Intent(getContext(), FileViewActivity.class); }
if(!fileStructure.getText().toString().equals("Root")) { @Override
public void onNavigateNewLocation(BreadcrumbItem newItem, int changedPosition) {
intent.putExtra("singleFileName", fileStructure.getText().toString()+"/"+fileName); }
} });
else {
intent.putExtra("singleFileName", fileName); fetchDataAsyncSub(instanceUrl, Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, finalDirName_);
}
Objects.requireNonNull(getContext()).startActivity(intent); }
}
private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) { @Override
public void onClickFile(String fileName) {
mRecyclerView.setVisibility(View.GONE); Intent intent = new Intent(getContext(), FileViewActivity.class);
mProgressBar.setVisibility(View.VISIBLE);
FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class); if(!fileStructure.getText().toString().equals("Root")) {
filesModel.getFilesList(instanceUrl, instanceToken, owner, repo, getContext()).observe(getViewLifecycleOwner(), new Observer<List<Files>>() { intent.putExtra("singleFileName", fileStructure.getText().toString() + "/" + fileName);
@Override }
public void onChanged(@Nullable List<Files> filesListMain) { else {
adapter = new FilesAdapter(getContext(), filesListMain, FilesFragment.this);
mBreadcrumbsView.removeItemAfter(1); intent.putExtra("singleFileName", fileName);
if(adapter.getItemCount() > 0) { }
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
mRecyclerView.setVisibility(View.VISIBLE);
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
} Objects.requireNonNull(getContext()).startActivity(intent);
}
private void fetchDataAsyncSub(String instanceUrl, String instanceToken, String owner, String repo, String filesDir) { private void fetchDataAsync(String instanceUrl, String instanceToken, String owner, String repo) {
mRecyclerView.setVisibility(View.GONE); mRecyclerView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);
FilesViewModel filesModel2 = new ViewModelProvider(this).get(FilesViewModel.class); FilesViewModel filesModel = new ViewModelProvider(this).get(FilesViewModel.class);
filesModel2.getFilesList2(instanceUrl, instanceToken, owner, repo, filesDir, getContext()).observe(this, new Observer<List<Files>>() { filesModel.getFilesList(instanceUrl, instanceToken, owner, repo, getContext()).observe(getViewLifecycleOwner(), new Observer<List<Files>>() {
@Override
public void onChanged(@Nullable List<Files> filesListMain2) {
adapter = new FilesAdapter(getContext(), filesListMain2, FilesFragment.this);
if(adapter.getItemCount() > 0) {
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
mRecyclerView.setVisibility(View.VISIBLE);
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
} @Override
public void onChanged(@Nullable List<Files> filesListMain) {
@Override adapter = new FilesAdapter(getContext(), filesListMain, FilesFragment.this);
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getContext())); mBreadcrumbsView.removeItemAfter(1);
if(adapter.getItemCount() > 0) {
mRecyclerView.setVisibility(View.VISIBLE);
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
mRecyclerView.setVisibility(View.VISIBLE);
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
inflater.inflate(R.menu.search_menu, menu); }
super.onCreateOptionsMenu(menu, inflater);
MenuItem searchItem = menu.findItem(R.id.action_search); private void fetchDataAsyncSub(String instanceUrl, String instanceToken, String owner, String repo, String filesDir) {
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
//searchView.setQueryHint(getContext().getString(R.string.search));
/*if(!connToInternet) { mRecyclerView.setVisibility(View.GONE);
return; mProgressBar.setVisibility(View.VISIBLE);
}*/
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { FilesViewModel filesModel2 = new ViewModelProvider(this).get(FilesViewModel.class);
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override filesModel2.getFilesList2(instanceUrl, instanceToken, owner, repo, filesDir, getContext()).observe(this, new Observer<List<Files>>() {
public boolean onQueryTextChange(String newText) {
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});
} @Override
public void onChanged(@Nullable List<Files> filesListMain2) {
public void onButtonPressed(Uri uri) { adapter = new FilesAdapter(getContext(), filesListMain2, FilesFragment.this);
if (mListener != null) { if(adapter.getItemCount() > 0) {
mListener.onFragmentInteraction(uri); mRecyclerView.setVisibility(View.VISIBLE);
} mRecyclerView.setAdapter(adapter);
} filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.GONE);
}
else {
mRecyclerView.setVisibility(View.VISIBLE);
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
filesFrame.setVisibility(View.VISIBLE);
noDataFiles.setVisibility(View.VISIBLE);
}
filesFrame.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
});
@Override }
public void onDetach() {
super.onDetach(); @Override
mListener = null; public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
}
inflater.inflate(R.menu.search_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
if(mRecyclerView.getAdapter() != null) {
adapter.getFilter().filter(newText);
}
return false;
}
});
}
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);
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
} }

View File

@ -1,311 +0,0 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.adapters.IssuesAdapter;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.mikepenz.fastadapter.IItemAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter;
import com.mikepenz.fastadapter.listeners.ItemFilterListener;
import com.mikepenz.fastadapter_extensions.items.ProgressItem;
import com.mikepenz.fastadapter_extensions.scroll.EndlessRecyclerOnScrollListener;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.mikepenz.fastadapter.adapters.ItemAdapter.items;
/**
* Author M M Arif
*/
public class IssuesClosedFragment extends Fragment implements ItemFilterListener<IssuesAdapter> {
private Context ctx;
private ProgressBar mProgressBarClosed;
private boolean loadNextFlag = false;
private String TAG = StaticGlobalVariables.tagIssuesListClosed;
private TextView noDataIssuesClosed;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private String requestType = StaticGlobalVariables.issuesRequestType;
private String issueState = StaticGlobalVariables.issueStateClosed;
private List<IssuesAdapter> items = new ArrayList<>();
private FastItemAdapter<IssuesAdapter> fastItemAdapter;
private ItemAdapter footerAdapter;
private EndlessRecyclerOnScrollListener endlessRecyclerOnScrollListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_issues_closed, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
if (VersionCheck.compareVersion("1.12.0", tinyDb.getString("giteaVersion")) < 1) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
}
noDataIssuesClosed = v.findViewById(R.id.noDataIssuesClosed);
mProgressBarClosed = v.findViewById(R.id.progress_barClosed);
final SwipeRefreshLayout swipeRefreshLayout = v.findViewById(R.id.pullToRefreshClosed);
RecyclerView recyclerView = v.findViewById(R.id.recyclerViewClosed);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(true);
fastItemAdapter = new FastItemAdapter<>();
fastItemAdapter.withSelectable(true);
footerAdapter = items();
//noinspection unchecked
fastItemAdapter.addAdapter(StaticGlobalVariables.issuesPageInit, footerAdapter);
fastItemAdapter.getItemFilter().withFilterPredicate((IItemAdapter.Predicate<IssuesAdapter>) (item, constraint) -> item.getIssueTitle().toLowerCase().contains(constraint.toString().toLowerCase()));
fastItemAdapter.getItemFilter().withItemFilterListener(this);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(fastItemAdapter);
endlessRecyclerOnScrollListener = new EndlessRecyclerOnScrollListener(footerAdapter) {
@Override
public void onLoadMore(final int currentPage) {
loadNext(instanceUrl, instanceToken, repoOwner, repoName, resultLimit, issueState, requestType, currentPage);
}
};
swipeRefreshLayout.setOnRefreshListener(() -> {
mProgressBarClosed.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
swipeRefreshLayout.setRefreshing(false);
});
recyclerView.addOnScrollListener(endlessRecyclerOnScrollListener);
loadInitial(instanceUrl, instanceToken, repoOwner, repoName, issueState, resultLimit, requestType);
fastItemAdapter.withEventHook(new IssuesAdapter.IssueTitleClickEvent());
assert savedInstanceState != null;
fastItemAdapter.withSavedInstanceState(savedInstanceState);
return v;
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getContext());
if(tinyDb.getBoolean("resumeClosedIssues")) {
mProgressBarClosed.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
tinyDb.putBoolean("resumeClosedIssues", false);
}
}
private void loadInitial(String instanceUrl, String token, String repoOwner, String repoName, String issueState, int resultLimit, String requestType) {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getClosedIssues(token, repoOwner, repoName, 1, issueState, resultLimit, requestType);
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;
if(response.body().size() > 0) {
if(response.body().size() == resultLimit) {
loadNextFlag = true;
}
for(int i = 0; i < response.body().size(); i++) {
items.add(new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
fastItemAdapter.add(items);
noDataIssuesClosed.setVisibility(View.GONE);
}
else {
noDataIssuesClosed.setVisibility(View.VISIBLE);
}
mProgressBarClosed.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadNext(String instanceUrl, String token, String repoOwner, String repoName, int resultLimit, String issueState, String requestType, final int currentPage) {
footerAdapter.clear();
//noinspection unchecked
footerAdapter.add(new ProgressItem().withEnabled(false));
Handler handler = new Handler();
handler.postDelayed(() -> {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getClosedIssues(token, repoOwner, repoName, currentPage + 1, issueState, resultLimit, requestType);
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;
if(response.body().size() > 0) {
loadNextFlag = response.body().size() == resultLimit;
for(int i = 0; i < response.body().size(); i++) {
fastItemAdapter.add(fastItemAdapter.getAdapterItemCount(), new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
footerAdapter.clear();
mProgressBarClosed.setVisibility(View.GONE);
}
else {
footerAdapter.clear();
}
mProgressBarClosed.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.i(TAG, t.toString());
}
});
}, 1000);
if(!loadNextFlag) {
footerAdapter.clear();
}
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
inflater.inflate(R.menu.search_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
fastItemAdapter.filter(newText);
return true;
}
});
endlessRecyclerOnScrollListener.enable();
}
@Override
public void itemsFiltered(@Nullable CharSequence constraint, @Nullable List<IssuesAdapter> results) {
endlessRecyclerOnScrollListener.disable();
}
@Override
public void onReset() {
endlessRecyclerOnScrollListener.enable();
}
}

View File

@ -0,0 +1,312 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.adapters.IssuesAdapter;
import org.mian.gitnex.clients.IssuesService;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.interfaces.ApiInterface;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class IssuesFragment extends Fragment {
private Menu menu;
private RecyclerView recyclerView;
private List<Issues> issuesList;
private IssuesAdapter adapter;
private ApiInterface api;
private Context context;
private int pageSize = StaticGlobalVariables.issuesPageInit;
private ProgressBar mProgressBar;
private String TAG = StaticGlobalVariables.tagIssuesList;
private TextView noDataIssues;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private String requestType = StaticGlobalVariables.issuesRequestType;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_issues, container, false);
setHasOptionsMenu(true);
context = getContext();
TinyDB tinyDb = new TinyDB(getContext());
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final SwipeRefreshLayout swipeRefresh = v.findViewById(R.id.pullToRefresh);
// if gitea is 1.12 or higher use the new limit
if(VersionCheck.compareVersion("1.12.0", tinyDb.getString("giteaVersion")) < 1) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
}
recyclerView = v.findViewById(R.id.recyclerView);
issuesList = new ArrayList<>();
mProgressBar = v.findViewById(R.id.progress_bar);
noDataIssues = v.findViewById(R.id.noDataIssues);
swipeRefresh.setOnRefreshListener(() -> new Handler().postDelayed(() -> {
swipeRefresh.setRefreshing(false);
loadInitial(instanceToken, repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"));
adapter.notifyDataChanged();
}, 200));
adapter = new IssuesAdapter(getContext(), issuesList);
adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
if(issuesList.size() == resultLimit || pageSize == resultLimit) {
int page = (issuesList.size() + resultLimit) / resultLimit;
loadMore(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState"));
}
}));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(adapter);
((RepoDetailActivity) Objects.requireNonNull(getActivity())).setFragmentRefreshListener(issueState -> {
if(issueState.equals("closed")) {
menu.getItem(1).setIcon(R.drawable.ic_filter_closed);
}
else {
menu.getItem(1).setIcon(R.drawable.ic_filter);
}
issuesList.clear();
adapter = new IssuesAdapter(getContext(), issuesList);
tinyDb.putString("repoIssuesState", issueState);
mProgressBar.setVisibility(View.VISIBLE);
noDataIssues.setVisibility(View.GONE);
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, resultLimit, requestType, issueState);
recyclerView.setAdapter(adapter);
});
api = IssuesService.createService(ApiInterface.class, instanceUrl, getContext());
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"));
return v;
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getContext());
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(tinyDb.getBoolean("resumeIssues")) {
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"));
tinyDb.putBoolean("resumeIssues", false);
}
}
private void loadInitial(String token, String repoOwner, String repoName, int resultLimit, String requestType, String issueState) {
Call<List<Issues>> call = api.getIssues(token, repoOwner, repoName, 1, resultLimit, requestType, issueState);
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;
if(response.body().size() > 0) {
issuesList.clear();
issuesList.addAll(response.body());
adapter.notifyDataChanged();
noDataIssues.setVisibility(View.GONE);
}
else {
issuesList.clear();
adapter.notifyDataChanged();
noDataIssues.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadMore(String token, String repoOwner, String repoName, int page, int resultLimit, String requestType, String issueState) {
//add loading progress view
issuesList.add(new Issues("load"));
adapter.notifyItemInserted((issuesList.size() - 1));
Call<List<Issues>> call = api.getIssues(token, repoOwner, repoName, page, resultLimit, requestType, issueState);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
//remove loading view
issuesList.remove(issuesList.size() - 1);
List<Issues> result = response.body();
assert result != null;
if(result.size() > 0) {
pageSize = result.size();
issuesList.addAll(result);
}
else {
Toasty.info(context, getString(R.string.noMoreData));
adapter.setMoreDataAvailable(false);
}
adapter.notifyDataChanged();
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
this.menu = menu;
inflater.inflate(R.menu.search_menu, menu);
inflater.inflate(R.menu.filter_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
TinyDB tinyDb = new TinyDB(context);
if(tinyDb.getString("repoIssuesState").equals("closed")) {
menu.getItem(1).setIcon(R.drawable.ic_filter_closed);
}
else {
menu.getItem(1).setIcon(R.drawable.ic_filter);
}
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
filter(newText);
return false;
}
});
}
private void filter(String text) {
List<Issues> arr = new ArrayList<>();
for(Issues d : issuesList) {
if(d.getTitle().toLowerCase().contains(text) || d.getBody().toLowerCase().contains(text)) {
arr.add(d);
}
}
adapter.updateList(arr);
}
}

View File

@ -1,155 +0,0 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.google.android.material.tabs.TabLayout;
import org.mian.gitnex.R;
import org.mian.gitnex.util.TinyDB;
import java.util.Objects;
/**
* Author M M Arif
*/
public class IssuesMainFragment extends Fragment {
private Context ctx;
public IssuesMainFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_issues_main, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext());
SectionsPagerAdapter mSectionsPagerAdapter = new IssuesMainFragment.SectionsPagerAdapter(getChildFragmentManager());
ViewPager mViewPager = v.findViewById(R.id.issuesContainer);
mViewPager.setAdapter(mSectionsPagerAdapter);
Typeface myTypeface;
if(tinyDb.getInt("customFontId") == 0) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/roboto.ttf");
}
else if (tinyDb.getInt("customFontId") == 1) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/manroperegular.ttf");
}
else if (tinyDb.getInt("customFontId") == 2) {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/sourcecodeproregular.ttf");
}
else {
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getContext()).getAssets(), "fonts/roboto.ttf");
}
TabLayout tabLayout = v.findViewById(R.id.tabs);
ViewGroup vg = (ViewGroup) tabLayout.getChildAt(0);
int tabsCount = vg.getChildCount();
for (int j = 0; j < tabsCount; j++) {
ViewGroup vgTab = (ViewGroup) vg.getChildAt(j);
int tabChildCount = vgTab.getChildCount();
for (int i = 0; i < tabChildCount; i++) {
View tabViewChild = vgTab.getChildAt(i);
if (tabViewChild instanceof TextView) {
((TextView) tabViewChild).setTypeface(myTypeface);
}
}
}
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
return v;
}
public static class SectionsPagerAdapter extends FragmentStatePagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
}
@NonNull
@Override
public Fragment getItem(int position) {
Fragment fragment = null;
switch (position) {
case 0: // open issues
fragment = new IssuesOpenFragment();
break;
case 1: // closed issues
fragment = new IssuesClosedFragment();
break;
}
assert fragment != null;
return fragment;
}
@Override
public int getCount() {
return 2;
}
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
menu.clear();
Objects.requireNonNull(getActivity()).getMenuInflater().inflate(R.menu.repo_dotted_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
return true;
case R.id.repoMenu:
BottomSheetRepoFragment bottomSheet = new BottomSheetRepoFragment();
bottomSheet.show(getChildFragmentManager(), "repoBottomSheet");
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -1,308 +0,0 @@
package org.mian.gitnex.fragments;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import android.os.Handler;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.mikepenz.fastadapter.IItemAdapter;
import com.mikepenz.fastadapter.adapters.ItemAdapter;
import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter;
import com.mikepenz.fastadapter.listeners.ItemFilterListener;
import com.mikepenz.fastadapter_extensions.items.ProgressItem;
import com.mikepenz.fastadapter_extensions.scroll.EndlessRecyclerOnScrollListener;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.adapters.IssuesAdapter;
import org.mian.gitnex.models.Issues;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import static com.mikepenz.fastadapter.adapters.ItemAdapter.items;
/**
* Author M M Arif
*/
public class IssuesOpenFragment extends Fragment implements ItemFilterListener<IssuesAdapter> {
private ProgressBar mProgressBar;
private boolean loadNextFlag = false;
private String TAG = StaticGlobalVariables.tagIssuesListOpen;
private TextView noDataIssues;
private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
private String requestType = StaticGlobalVariables.issuesRequestType;
private List<IssuesAdapter> items = new ArrayList<>();
private FastItemAdapter<IssuesAdapter> fastItemAdapter;
private ItemAdapter footerAdapter;
private EndlessRecyclerOnScrollListener endlessRecyclerOnScrollListener;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_issues, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext());
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
if (VersionCheck.compareVersion("1.12.0", tinyDb.getString("giteaVersion")) < 1) {
resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
}
noDataIssues = v.findViewById(R.id.noDataIssues);
mProgressBar = v.findViewById(R.id.progress_bar);
final SwipeRefreshLayout swipeRefreshLayout = v.findViewById(R.id.pullToRefresh);
RecyclerView recyclerView = v.findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(true);
fastItemAdapter = new FastItemAdapter<>();
fastItemAdapter.withSelectable(true);
footerAdapter = items();
//noinspection unchecked
fastItemAdapter.addAdapter(StaticGlobalVariables.issuesPageInit, footerAdapter);
fastItemAdapter.getItemFilter().withFilterPredicate((IItemAdapter.Predicate<IssuesAdapter>) (item, constraint) -> item.getIssueTitle().toLowerCase().contains(constraint.toString().toLowerCase()));
fastItemAdapter.getItemFilter().withItemFilterListener(this);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(fastItemAdapter);
endlessRecyclerOnScrollListener = new EndlessRecyclerOnScrollListener(footerAdapter) {
@Override
public void onLoadMore(final int currentPage) {
loadNext(instanceUrl, instanceToken, repoOwner, repoName, resultLimit, requestType, currentPage);
}
};
swipeRefreshLayout.setOnRefreshListener(() -> {
mProgressBar.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
swipeRefreshLayout.setRefreshing(false);
});
recyclerView.addOnScrollListener(endlessRecyclerOnScrollListener);
loadInitial(instanceUrl, instanceToken, repoOwner, repoName, resultLimit, requestType);
fastItemAdapter.withEventHook(new IssuesAdapter.IssueTitleClickEvent());
assert savedInstanceState != null;
fastItemAdapter.withSavedInstanceState(savedInstanceState);
return v;
}
@Override
public void onResume() {
super.onResume();
TinyDB tinyDb = new TinyDB(getContext());
if(tinyDb.getBoolean("resumeIssues")) {
mProgressBar.setVisibility(View.VISIBLE);
fastItemAdapter.clear();
endlessRecyclerOnScrollListener.resetPageCount();
tinyDb.putBoolean("resumeIssues", false);
}
}
private void loadInitial(String instanceUrl, String token, String repoOwner, String repoName, int resultLimit, String requestType) {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getIssues(token, repoOwner, repoName, 1, resultLimit, requestType);
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;
if(response.body().size() > 0) {
if(response.body().size() == resultLimit) {
loadNextFlag = true;
}
for(int i = 0; i < response.body().size(); i++) {
items.add(new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
fastItemAdapter.add(items);
noDataIssues.setVisibility(View.GONE);
}
else {
noDataIssues.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadNext(String instanceUrl, String token, String repoOwner, String repoName, int resultLimit, String requestType, final int currentPage) {
footerAdapter.clear();
//noinspection unchecked
footerAdapter.add(new ProgressItem().withEnabled(false));
Handler handler = new Handler();
handler.postDelayed(() -> {
Call<List<Issues>> call = RetrofitClient.getInstance(instanceUrl, getContext()).getApiInterface().getIssues(token, repoOwner, repoName, currentPage + 1, resultLimit, requestType);
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;
if(response.body().size() > 0) {
loadNextFlag = response.body().size() == resultLimit;
for(int i = 0; i < response.body().size(); i++) {
fastItemAdapter.add(fastItemAdapter.getAdapterItemCount(), new IssuesAdapter(getContext()).withNewItems(response.body().get(i).getTitle(), response.body().get(i).getNumber(), response.body().get(i).getUser().getAvatar_url(), response.body().get(i).getCreated_at(), response.body().get(i).getComments(), response.body().get(i).getUser().getFull_name(), response.body().get(i).getUser().getLogin()));
}
footerAdapter.clear();
noDataIssues.setVisibility(View.GONE);
}
else {
footerAdapter.clear();
}
mProgressBar.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.i(TAG, t.toString());
}
});
}, 1000);
if(!loadNextFlag) {
footerAdapter.clear();
}
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
inflater.inflate(R.menu.search_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
fastItemAdapter.filter(newText);
return true;
}
});
endlessRecyclerOnScrollListener.enable();
}
@Override
public void itemsFiltered(@Nullable CharSequence constraint, @Nullable List<IssuesAdapter> results) {
endlessRecyclerOnScrollListener.disable();
}
@Override
public void onReset() {
endlessRecyclerOnScrollListener.enable();
}
}

View File

@ -2,13 +2,6 @@ package org.mian.gitnex.fragments;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -20,14 +13,23 @@ import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.adapters.PullRequestsAdapter; import org.mian.gitnex.adapters.PullRequestsAdapter;
import org.mian.gitnex.clients.PullRequestsService; import org.mian.gitnex.clients.PullRequestsService;
import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.StaticGlobalVariables;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.interfaces.ApiInterface; import org.mian.gitnex.interfaces.ApiInterface;
import org.mian.gitnex.models.PullRequests; import org.mian.gitnex.models.PullRequests;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB; import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -42,254 +44,274 @@ import retrofit2.Response;
public class PullRequestsFragment extends Fragment { public class PullRequestsFragment extends Fragment {
private ProgressBar mProgressBar; private Menu menu;
private RecyclerView recyclerView; private ProgressBar mProgressBar;
private List<PullRequests> prList; private RecyclerView recyclerView;
private PullRequestsAdapter adapter; private List<PullRequests> prList;
private ApiInterface apiPR; private PullRequestsAdapter adapter;
private String TAG = "PullRequestsListFragment - "; private ApiInterface apiPR;
private Context context; private String TAG = StaticGlobalVariables.tagPullRequestsList;
private int pageSize = 1; private Context context;
private TextView noData; private int pageSize = StaticGlobalVariables.prPageInit;
private String prState = "open"; private TextView noData;
private int resultLimit = 50; private int resultLimit = StaticGlobalVariables.resultLimitOldGiteaInstances;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
final View v = inflater.inflate(R.layout.fragment_pull_requests, container, false);
setHasOptionsMenu(true);
TinyDB tinyDb = new TinyDB(getContext()); @Nullable
String repoFullName = tinyDb.getString("repoFullName"); @Override
//Log.i("repoFullName", tinyDb.getString("repoFullName")); public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final SwipeRefreshLayout swipeRefresh = v.findViewById(R.id.pullToRefresh); final View v = inflater.inflate(R.layout.fragment_pull_requests, container, false);
setHasOptionsMenu(true);
context = getContext();
context = getContext(); TinyDB tinyDb = new TinyDB(getContext());
recyclerView = v.findViewById(R.id.recyclerView); String repoFullName = tinyDb.getString("repoFullName");
prList = new ArrayList<>(); String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
mProgressBar = v.findViewById(R.id.progress_bar); final SwipeRefreshLayout swipeRefresh = v.findViewById(R.id.pullToRefresh);
noData = v.findViewById(R.id.noData);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { // if gitea is 1.12 or higher use the new limit
@Override if(VersionCheck.compareVersion("1.12.0", tinyDb.getString("giteaVersion")) < 1) {
public void onRefresh() { resultLimit = StaticGlobalVariables.resultLimitNewGiteaInstances;
new Handler().postDelayed(new Runnable() { }
@Override
public void run() {
swipeRefresh.setRefreshing(false);
loadInitial(instanceToken, repoOwner, repoName, pageSize, prState, resultLimit);
adapter.notifyDataChanged();
}
}, 200);
}
});
adapter = new PullRequestsAdapter(getContext(), prList);
adapter.setLoadMoreListener(new PullRequestsAdapter.OnLoadMoreListener() {
@Override
public void onLoadMore() {
recyclerView.post(new Runnable() { recyclerView = v.findViewById(R.id.recyclerView);
@Override prList = new ArrayList<>();
public void run() {
if(prList.size() == 10 || pageSize == 10) {
int page = (prList.size() + 10) / 10; mProgressBar = v.findViewById(R.id.progress_bar);
loadMore(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, page, prState, resultLimit); noData = v.findViewById(R.id.noData);
} swipeRefresh.setOnRefreshListener(() -> new Handler().postDelayed(() -> {
/*else {
Toasty.info(context, getString(R.string.noMoreData)); swipeRefresh.setRefreshing(false);
loadInitial(instanceToken, repoOwner, repoName, pageSize, tinyDb.getString("repoPrState"), resultLimit);
adapter.notifyDataChanged();
}*/ }, 200));
}
});
} adapter = new PullRequestsAdapter(getContext(), prList);
}); adapter.setLoadMoreListener(() -> recyclerView.post(() -> {
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), if(prList.size() == 10 || pageSize == resultLimit) {
DividerItemDecoration.VERTICAL);
recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(adapter);
apiPR = PullRequestsService.createService(ApiInterface.class, instanceUrl, getContext()); int page = (prList.size() + resultLimit) / resultLimit;
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, pageSize, prState, resultLimit); loadMore(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, page, tinyDb.getString("repoPrState"), resultLimit);
return v; }
} }));
@Override DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL);
public void onResume() { recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(adapter);
super.onResume(); ((RepoDetailActivity) Objects.requireNonNull(getActivity())).setFragmentRefreshListenerPr(prState -> {
TinyDB tinyDb = new TinyDB(getContext());
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(tinyDb.getBoolean("resumePullRequests")) { if(prState.equals("closed")) {
menu.getItem(1).setIcon(R.drawable.ic_filter_closed);
}
else {
menu.getItem(1).setIcon(R.drawable.ic_filter);
}
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, pageSize, prState, resultLimit); prList.clear();
tinyDb.putBoolean("resumePullRequests", false); adapter = new PullRequestsAdapter(context, prList);
tinyDb.putBoolean("prMerged", false); tinyDb.putString("repoPrState", prState);
mProgressBar.setVisibility(View.VISIBLE);
noData.setVisibility(View.GONE);
loadInitial(Authorization.returnAuthentication(context, loginUid, instanceToken), repoOwner, repoName, pageSize, prState, resultLimit);
recyclerView.setAdapter(adapter);
} });
} apiPR = PullRequestsService.createService(ApiInterface.class, instanceUrl, context);
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, pageSize, tinyDb.getString("repoPrState"), resultLimit);
private void loadInitial(String token, String repoOwner, String repoName, int page, String prState, int resultLimit) { return v;
Call<List<PullRequests>> call = apiPR.getPullRequests(token, repoOwner, repoName, page, prState, resultLimit); }
call.enqueue(new Callback<List<PullRequests>>() { @Override
public void onResume() {
@Override super.onResume();
public void onResponse(@NonNull Call<List<PullRequests>> call, @NonNull Response<List<PullRequests>> response) { TinyDB tinyDb = new TinyDB(getContext());
final String loginUid = tinyDb.getString("loginUid");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
if(response.isSuccessful()) { if(tinyDb.getBoolean("resumePullRequests")) {
assert response.body() != null; loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, pageSize, tinyDb.getString("repoPrState"), resultLimit);
if(response.body().size() > 0) { tinyDb.putBoolean("resumePullRequests", false);
tinyDb.putBoolean("prMerged", false);
prList.clear(); }
prList.addAll(response.body());
adapter.notifyDataChanged();
noData.setVisibility(View.GONE);
} }
else {
prList.clear();
adapter.notifyDataChanged();
noData.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
Log.i("http", String.valueOf(response.code())); private void loadInitial(String token, String repoOwner, String repoName, int page, String prState, int resultLimit) {
} Call<List<PullRequests>> call = apiPR.getPullRequests(token, repoOwner, repoName, page, prState, resultLimit);
@Override call.enqueue(new Callback<List<PullRequests>>() {
public void onFailure(@NonNull Call<List<PullRequests>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
}); @Override
public void onResponse(@NonNull Call<List<PullRequests>> call, @NonNull Response<List<PullRequests>> response) {
} if(response.isSuccessful()) {
private void loadMore(String token, String repoOwner, String repoName, int page, String prState, int resultLimit){ assert response.body() != null;
if(response.body().size() > 0) {
//add loading progress view prList.clear();
prList.add(new PullRequests("load")); prList.addAll(response.body());
adapter.notifyItemInserted((prList.size() - 1)); adapter.notifyDataChanged();
noData.setVisibility(View.GONE);
Call<List<PullRequests>> call = apiPR.getPullRequests(token, repoOwner, repoName, page, prState, resultLimit); }
else {
prList.clear();
adapter.notifyDataChanged();
noData.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
}
else {
Log.i(TAG, String.valueOf(response.code()));
}
call.enqueue(new Callback<List<PullRequests>>() { Log.i(TAG, String.valueOf(response.code()));
@Override }
public void onResponse(@NonNull Call<List<PullRequests>> call, @NonNull Response<List<PullRequests>> response) {
if(response.isSuccessful()){ @Override
public void onFailure(@NonNull Call<List<PullRequests>> call, @NonNull Throwable t) {
//remove loading view Log.e(TAG, t.toString());
prList.remove(prList.size()-1); }
List<PullRequests> result = response.body(); });
assert result != null; }
if(result.size() > 0) {
pageSize = result.size(); private void loadMore(String token, String repoOwner, String repoName, int page, String prState, int resultLimit) {
prList.addAll(result);
} //add loading progress view
else { prList.add(new PullRequests("load"));
adapter.notifyItemInserted((prList.size() - 1));
Toasty.info(context, getString(R.string.noMoreData)); Call<List<PullRequests>> call = apiPR.getPullRequests(token, repoOwner, repoName, page, prState, resultLimit);
adapter.setMoreDataAvailable(false);
} call.enqueue(new Callback<List<PullRequests>>() {
adapter.notifyDataChanged(); @Override
public void onResponse(@NonNull Call<List<PullRequests>> call, @NonNull Response<List<PullRequests>> response) {
} if(response.isSuccessful()) {
else {
Log.e(TAG, String.valueOf(response.code())); //remove loading view
prList.remove(prList.size() - 1);
} List<PullRequests> result = response.body();
} assert result != null;
if(result.size() > 0) {
@Override pageSize = result.size();
public void onFailure(@NonNull Call<List<PullRequests>> call, @NonNull Throwable t) { prList.addAll(result);
Log.e(TAG, t.toString()); }
else {
} Toasty.info(context, getString(R.string.noMoreData));
adapter.setMoreDataAvailable(false);
}); }
}
@Override adapter.notifyDataChanged();
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
boolean connToInternet = AppUtil.haveNetworkConnection(Objects.requireNonNull(getContext())); }
else {
inflater.inflate(R.menu.search_menu, menu); Log.e(TAG, String.valueOf(response.code()));
super.onCreateOptionsMenu(menu, inflater);
MenuItem searchItem = menu.findItem(R.id.action_search); }
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
//searchView.setQueryHint(getContext().getString(R.string.strFilter));
/*if(!connToInternet) { }
return;
}*/
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() { @Override
public void onFailure(@NonNull Call<List<PullRequests>> call, @NonNull Throwable t) {
@Override Log.e(TAG, t.toString());
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override }
public boolean onQueryTextChange(String newText) {
adapter.getFilter().filter(newText); });
return false; }
} @Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
}); this.menu = menu;
inflater.inflate(R.menu.search_menu, menu);
inflater.inflate(R.menu.filter_menu_pr, menu);
super.onCreateOptionsMenu(menu, inflater);
} TinyDB tinyDb = new TinyDB(context);
if(tinyDb.getString("repoPrState").equals("closed")) {
menu.getItem(1).setIcon(R.drawable.ic_filter_closed);
}
else {
menu.getItem(1).setIcon(R.drawable.ic_filter);
}
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
searchView.setOnQueryTextListener(new androidx.appcompat.widget.SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
filter(newText);
return false;
}
});
}
private void filter(String text) {
List<PullRequests> arr = new ArrayList<>();
for(PullRequests d : prList) {
if(d.getTitle().toLowerCase().contains(text) || d.getBody().toLowerCase().contains(text)) {
arr.add(d);
}
}
adapter.updateList(arr);
}
} }

View File

@ -6,13 +6,17 @@ package org.mian.gitnex.helpers;
public interface StaticGlobalVariables { public interface StaticGlobalVariables {
// issues variables // generic values
String tagIssuesListOpen = "IssuesListOpenFragment - ";
String tagIssuesListClosed = "IssuesListClosedFragment - ";
int issuesPageInit = 1;
int resultLimitNewGiteaInstances = 25; // Gitea 1.12 and above int resultLimitNewGiteaInstances = 25; // Gitea 1.12 and above
int resultLimitOldGiteaInstances = 10; // Gitea 1.11 and below int resultLimitOldGiteaInstances = 10; // Gitea 1.11 and below
// issues variables
String tagIssuesList = "IssuesListFragment";
int issuesPageInit = 1;
String issuesRequestType = "issues"; String issuesRequestType = "issues";
String issueStateClosed = "closed";
// pull request
String tagPullRequestsList = "PullRequestsListFragment";
int prPageInit = 1;
} }

View File

@ -97,10 +97,7 @@ public interface ApiInterface {
Call<UserRepositories> getUserRepository(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName); Call<UserRepositories> getUserRepository(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
@GET("repos/{owner}/{repo}/issues") // get issues by repo @GET("repos/{owner}/{repo}/issues") // get issues by repo
Call<List<Issues>> getIssues(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Query("page") int page, @Query("limit") int limit, @Query("type") String requestType); Call<List<Issues>> getIssues(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Query("page") int page, @Query("limit") int limit, @Query("type") String requestType, @Query("state") String issueState);
@GET("repos/{owner}/{repo}/issues") // get closed issues by repo
Call<List<Issues>> getClosedIssues(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Query("page") int page, @Query("state") String issueState, @Query("limit") int limit, @Query("type") String requestType);
@GET("repos/{owner}/{repo}/issues/{index}") // get issue by id @GET("repos/{owner}/{repo}/issues/{index}") // get issue by id
Call<Issues> getIssueByIndex(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int issueIndex); Call<Issues> getIssueByIndex(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int issueIndex);

View File

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#AF4242" android:viewportHeight="24.0"
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
</vector>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
android:background="?attr/primaryBackgroundColor"
android:paddingTop="8dp">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:id="@+id/openIssues"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/tabIssueOpen"
android:drawableStart="@drawable/ic_issue_open"
android:drawablePadding="24dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:padding="16dp" />
<TextView
android:id="@+id/closedIssues"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/tabIssueClosed"
android:drawableStart="@drawable/ic_done"
android:drawablePadding="24dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:padding="16dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
android:background="?attr/primaryBackgroundColor"
android:paddingTop="8dp">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:id="@+id/openPr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/tabIssueOpen"
android:drawableStart="@drawable/ic_merge"
android:drawablePadding="24dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:padding="16dp" />
<TextView
android:id="@+id/closedPr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/tabIssueClosed"
android:drawableStart="@drawable/ic_done"
android:drawablePadding="24dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:padding="16dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/filter"
android:icon="@drawable/ic_filter"
android:title="@string/strFilter"
android:orderInCategory="0"
app:showAsAction="ifRoom" />
</menu>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/filterPr"
android:icon="@drawable/ic_filter"
android:title="@string/strFilter"
android:orderInCategory="0"
app:showAsAction="ifRoom" />
</menu>