My issues / update assignees list (#1087)

Closes #745
Closes #200

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1087
Reviewed-by: qwerty287 <qwerty287@noreply.codeberg.org>
This commit is contained in:
M M Arif 2022-03-18 09:57:24 +01:00
parent 5761c3519e
commit 84e8850d9f
24 changed files with 357 additions and 196 deletions

View File

@ -109,7 +109,7 @@ dependencies {
implementation "androidx.work:work-runtime:$work_version"
implementation "io.mikael:urlbuilder:2.0.9"
implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2"
implementation "org.codeberg.gitnex:tea4j:1.1.1"
implementation "org.codeberg.gitnex:tea4j:1.1.3"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'com.github.chrisvest:stormpot:2.4.2'

View File

@ -13,7 +13,6 @@ import org.mian.gitnex.adapters.AssigneesListAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.CustomAssigneesSelectionDialogBinding;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.contexts.AccountContext;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
@ -66,7 +65,7 @@ public class AssigneesActions {
Call<List<Collaborators>> call = RetrofitClient
.getApiInterface(ctx)
.getCollaborators(((BaseActivity) ctx).getAccount().getAuthorization(), repoOwner, repoName);
.getAllAssignees(((BaseActivity) ctx).getAccount().getAuthorization(), repoOwner, repoName);
call.enqueue(new Callback<List<Collaborators>>() {
@ -85,8 +84,6 @@ public class AssigneesActions {
if(assigneesList_.size() > 0) {
AccountContext userInfo = ((BaseActivity) ctx).getAccount();
assigneesList.add(new Collaborators(userInfo.getFullName(), userInfo.getAccount().getUserName(), userInfo.getUserInfo().getAvatar()));
assigneesList.addAll(assigneesList_);
}
else {

View File

@ -175,7 +175,7 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
View view = assigneesBinding.getRoot();
dialogAssignees.setContentView(view);
assigneesBinding.cancel.setOnClickListener(assigneesBinding_ -> dialogAssignees.dismiss());
assigneesBinding.save.setOnClickListener(assigneesBinding_ -> dialogAssignees.dismiss());
dialogAssignees.show();
AssigneesActions.getRepositoryAssignees(ctx, repository.getOwner(), repository.getName(), assigneesList, dialogAssignees, assigneesAdapter, assigneesBinding);
@ -195,7 +195,7 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
View view = labelsBinding.getRoot();
dialogLabels.setContentView(view);
labelsBinding.cancel.setOnClickListener(labelsBinding_ -> dialogLabels.dismiss());
labelsBinding.save.setOnClickListener(labelsBinding_ -> dialogLabels.dismiss());
dialogLabels.show();
LabelsActions.getRepositoryLabels(ctx, repository.getOwner(), repository.getName(), labelsList, dialogLabels, labelsAdapter, labelsBinding);

View File

@ -229,7 +229,7 @@ public class CreatePullRequestActivity extends BaseActivity implements LabelsLis
View view = labelsBinding.getRoot();
dialogLabels.setContentView(view);
labelsBinding.cancel.setOnClickListener(editProperties -> dialogLabels.dismiss());
labelsBinding.save.setOnClickListener(editProperties -> dialogLabels.dismiss());
dialogLabels.show();
LabelsActions.getRepositoryLabels(ctx, repository.getOwner(), repository.getName(), labelsList, dialogLabels, labelsAdapter, labelsBinding);

View File

@ -268,7 +268,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
assigneesAdapter.updateList(currentAssignees);
dialogAssignees = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
dialogAssignees.setCancelable(false);
dialogAssignees.setCancelable(true);
if (dialogAssignees.getWindow() != null) {
@ -280,7 +280,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
View view = assigneesBinding.getRoot();
dialogAssignees.setContentView(view);
assigneesBinding.cancel.setOnClickListener(assigneesBinding_ -> {
assigneesBinding.save.setOnClickListener(assigneesBinding_ -> {
currentAssignees = new ArrayList<>(new LinkedHashSet<>(currentAssignees));
assigneesListData = new ArrayList<>(new LinkedHashSet<>(assigneesListData));
@ -305,7 +305,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
labelsAdapter.updateList(currentLabelsIds);
dialogLabels = new Dialog(ctx, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert);
dialogLabels.setCancelable(false);
dialogLabels.setCancelable(true);
if (dialogLabels.getWindow() != null) {
@ -317,7 +317,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
View view = labelsBinding.getRoot();
dialogLabels.setContentView(view);
labelsBinding.cancel.setOnClickListener(labelsBinding_ -> {
labelsBinding.save.setOnClickListener(labelsBinding_ -> {
currentLabelsIds = new ArrayList<>(new LinkedHashSet<>(currentLabelsIds));
labelsIds = new ArrayList<>(new LinkedHashSet<>(labelsIds));

View File

@ -38,6 +38,7 @@ import org.mian.gitnex.fragments.AdministrationFragment;
import org.mian.gitnex.fragments.BottomSheetDraftsFragment;
import org.mian.gitnex.fragments.DraftsFragment;
import org.mian.gitnex.fragments.ExploreFragment;
import org.mian.gitnex.fragments.MyIssuesFragment;
import org.mian.gitnex.fragments.MyProfileFragment;
import org.mian.gitnex.fragments.MyRepositoriesFragment;
import org.mian.gitnex.fragments.NotificationsFragment;
@ -161,6 +162,9 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
else if(fragmentById instanceof AdministrationFragment) {
toolbarTitle.setText(getResources().getString(R.string.pageTitleAdministration));
}
else if(fragmentById instanceof MyIssuesFragment) {
toolbarTitle.setText(getResources().getString(R.string.navMyIssues));
}
getNotificationsCount(instanceToken);
@ -211,7 +215,6 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
userEmail.setTypeface(myTypeface);
userFullName.setTypeface(myTypeface);
if (getAccount().getUserInfo() != null) {
String userEmailNav = getAccount().getUserInfo().getEmail();
String userFullNameNav = getAccount().getFullName();
@ -272,6 +275,10 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
// hide first
navigationView.getMenu().findItem(R.id.nav_administration).setVisible(false);
}
if(getAccount().requiresVersion("1.14.0")) {
navigationView.getMenu().findItem(R.id.nav_my_issues).setVisible(true);
}
}
@Override
@ -401,6 +408,12 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
navigationView.setCheckedItem(R.id.nav_notifications);
break;
case 8:
toolbarTitle.setText(getResources().getString(R.string.navMyIssues));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyIssuesFragment()).commit();
navigationView.setCheckedItem(R.id.nav_my_issues);
break;
default:
toolbarTitle.setText(getResources().getString(R.string.navMyRepos));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyRepositoriesFragment()).commit();
@ -557,6 +570,11 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig
toolbarTitle.setText(getResources().getString(R.string.pageTitleAdministration));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new AdministrationFragment()).commit();
}
else if(id == R.id.nav_my_issues) {
toolbarTitle.setText(getResources().getString(R.string.navMyIssues));
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new MyIssuesFragment()).commit();
}
drawer.closeDrawer(GravityCompat.START);
return true;

View File

@ -26,6 +26,7 @@ import org.mian.gitnex.adapters.RepoForksAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityRepoForksBinding;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.contexts.RepositoryContext;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
@ -49,6 +50,8 @@ public class RepoForksActivity extends BaseActivity {
private RepoForksAdapter adapter;
private ProgressBar progressLoadMore;
private RepositoryContext repository;
@SuppressLint("DefaultLocale")
@Override
public void onCreate(Bundle savedInstanceState) {
@ -61,11 +64,9 @@ public class RepoForksActivity extends BaseActivity {
Toolbar toolbar = activityRepoForksBinding.toolbar;
setSupportActionBar(toolbar);
String repoFullNameForForks = getIntent().getStringExtra("repoFullNameForForks");
assert repoFullNameForForks != null;
String[] parts = repoFullNameForForks.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
repository = RepositoryContext.fromIntent(getIntent());
final String repoOwner = repository.getOwner();
final String repoName = repository.getName();
activityRepoForksBinding.toolbarTitle.setText(ctx.getResources().getString(R.string.infoTabRepoForksCount));
@ -75,10 +76,7 @@ public class RepoForksActivity extends BaseActivity {
progressBar = activityRepoForksBinding.progressBar;
SwipeRefreshLayout swipeRefresh = activityRepoForksBinding.pullToRefresh;
closeActivity.setOnClickListener(v -> {
getIntent().removeExtra("repoFullNameForForks");
finish();
});
closeActivity.setOnClickListener(v -> finish());
// if gitea is 1.12 or higher use the new limit (resultLimitNewGiteaInstances)
if(getAccount().requiresVersion("1.12")) {
@ -241,4 +239,9 @@ public class RepoForksActivity extends BaseActivity {
adapter.updateList(userRepositories);
}
@Override
public void onResume() {
super.onResume();
repository.checkAccountSwitch(this);
}
}

View File

@ -2,13 +2,10 @@ package org.mian.gitnex.activities;
import android.os.Bundle;
import android.view.View;
import android.widget.CompoundButton;
import androidx.appcompat.app.AlertDialog;
import com.google.android.material.switchmaterial.SwitchMaterial;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.ActivitySettingsGeneralBinding;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.Version;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -50,6 +47,11 @@ public class SettingsGeneralActivity extends BaseActivity {
}
homeScreenList = new ArrayList<>(Arrays.asList(appHomeDefaultScreen));
if(!getAccount().requiresVersion("1.14.0")) {
homeScreenList.remove(8);
}
String[] homeScreenArray = new String[homeScreenList.size()];
homeScreenList.toArray(homeScreenArray);
@ -87,6 +89,10 @@ public class SettingsGeneralActivity extends BaseActivity {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.pageTitleNotifications));
}
else if(homeScreenSelectedChoice == 8) {
viewBinding.homeScreenSelected.setText(getResources().getString(R.string.navMyIssues));
}
viewBinding.homeScreenFrame.setOnClickListener(setDefaultHomeScreen -> {

View File

@ -1,5 +1,6 @@
package org.mian.gitnex.adapters;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.Html;
import android.view.LayoutInflater;
@ -131,6 +132,7 @@ public class AssigneesListAdapter extends RecyclerView.Adapter<AssigneesListAdap
return assigneesList.size();
}
@SuppressLint("NotifyDataSetChanged")
public void updateList(List<String> list) {
currentAssignees = list;

View File

@ -43,7 +43,7 @@ public class ExploreIssuesAdapter extends RecyclerView.Adapter<RecyclerView.View
private final Context context;
private final int TYPE_LOAD = 0;
private List<Issues> searchedList;
private Runnable loadMoreListener;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final TinyDB tinyDb;
@ -69,7 +69,7 @@ public class ExploreIssuesAdapter extends RecyclerView.Adapter<RecyclerView.View
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
isLoading = true;
loadMoreListener.run();
loadMoreListener.onLoadMore();
}
if(getItemViewType(position) == TYPE_LOAD) {
@ -204,15 +204,24 @@ public class ExploreIssuesAdapter extends RecyclerView.Adapter<RecyclerView.View
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
if(!isMoreDataAvailable) {
loadMoreListener.onLoadFinished();
}
}
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
loadMoreListener.onLoadFinished();
}
public void setLoadMoreListener(Runnable loadMoreListener) {
public interface OnLoadMoreListener {
void onLoadMore();
void onLoadFinished();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}

View File

@ -4,7 +4,6 @@ import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -12,22 +11,15 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.gitnex.tea4j.models.Issues;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.adapters.ExploreIssuesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentSearchIssuesBinding;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.SnackBar;
import java.util.ArrayList;
import java.util.List;
import org.mian.gitnex.viewmodels.IssuesViewModel;
import java.util.Objects;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -36,22 +28,14 @@ import retrofit2.Response;
public class ExploreIssuesFragment extends Fragment {
private FragmentSearchIssuesBinding viewBinding;
private Context context;
private List<Issues> dataList;
private ExploreIssuesAdapter adapter;
private int pageSize;
private int page = 1;
private final String TAG = Constants.exploreIssues;
private final int resultLimit = Constants.resultLimitOldGiteaInstances; // search issues always return 10 records
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
viewBinding = FragmentSearchIssuesBinding.inflate(inflater, container, false);
context = getContext();
dataList = new ArrayList<>();
adapter = new ExploreIssuesAdapter(dataList, context);
viewBinding.searchKeyword.setOnEditorActionListener((v1, actionId, event) -> {
if(actionId == EditorInfo.IME_ACTION_SEND) {
@ -60,111 +44,70 @@ public class ExploreIssuesFragment extends Fragment {
imm.hideSoftInputFromWindow(viewBinding.searchKeyword.getWindowToken(), 0);
viewBinding.progressBar.setVisibility(View.VISIBLE);
loadInitial(String.valueOf(viewBinding.searchKeyword.getText()), resultLimit);
adapter.setLoadMoreListener(() -> viewBinding.recyclerViewSearchIssues.post(() -> {
if(dataList.size() == resultLimit || pageSize == resultLimit) {
int page = (dataList.size() + resultLimit) / resultLimit;
loadMore(String.valueOf(viewBinding.searchKeyword.getText()), resultLimit, page);
}
}));
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization(), String.valueOf(viewBinding.searchKeyword.getText()));
}
}
return false;
});
viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
viewBinding.pullToRefresh.setRefreshing(false);
loadInitial("", resultLimit);
adapter.notifyDataChanged();
}, 200));
adapter.setLoadMoreListener(() -> viewBinding.recyclerViewSearchIssues.post(() -> {
if(dataList.size() == resultLimit || pageSize == resultLimit) {
int page = (dataList.size() + resultLimit) / resultLimit;
loadMore(String.valueOf(viewBinding.searchKeyword.getText()), resultLimit, page);
if(!Objects.requireNonNull(viewBinding.searchKeyword.getText()).toString().equals("")) {
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization(), String.valueOf(viewBinding.searchKeyword.getText()));
}
}));
else {
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization(), "");
}
viewBinding.progressBar.setVisibility(View.VISIBLE);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(context, DividerItemDecoration.VERTICAL);
}, 50));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(requireActivity(), DividerItemDecoration.VERTICAL);
viewBinding.recyclerViewSearchIssues.setHasFixedSize(true);
viewBinding.recyclerViewSearchIssues.addItemDecoration(dividerItemDecoration);
viewBinding.recyclerViewSearchIssues.setLayoutManager(new LinearLayoutManager(context));
viewBinding.recyclerViewSearchIssues.setAdapter(adapter);
viewBinding.recyclerViewSearchIssues.setLayoutManager(new LinearLayoutManager(requireActivity()));
loadInitial("", resultLimit);
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization(), "");
return viewBinding.getRoot();
}
private void loadInitial(String searchKeyword, int resultLimit) {
private void fetchDataAsync(String instanceToken, String searchKeyword) {
IssuesViewModel issuesModel = new ViewModelProvider(this).get(IssuesViewModel.class);
issuesModel.getIssuesList(instanceToken, searchKeyword, "issues", null, "open", getContext()).observe(getViewLifecycleOwner(), issuesListMain -> {
adapter = new ExploreIssuesAdapter(issuesListMain, getContext());
adapter.setLoadMoreListener(new ExploreIssuesAdapter.OnLoadMoreListener() {
@Override
public void onLoadMore() {
page += 1;
IssuesViewModel.loadMoreIssues(instanceToken, searchKeyword, "issues", null, "open", page, getContext(), adapter);
viewBinding.progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadFinished() {
Call<List<Issues>> call = RetrofitClient
.getApiInterface(context).queryIssues(((BaseActivity) requireActivity()).getAccount().getAuthorization(), searchKeyword, "issues", "open", resultLimit, 1);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
if(response.body() != null && response.body().size() > 0) {
dataList.clear();
dataList.addAll(response.body());
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.GONE);
}
else {
dataList.clear();
adapter.notifyDataChanged();
viewBinding.noData.setVisibility(View.VISIBLE);
}
viewBinding.progressBar.setVisibility(View.GONE);
}
else if(response.code() == 404) {
viewBinding.noData.setVisibility(View.VISIBLE);
viewBinding.progressBar.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
});
if(adapter.getItemCount() > 0) {
viewBinding.recyclerViewSearchIssues.setAdapter(adapter);
viewBinding.noData.setVisibility(View.GONE);
}
else {
adapter.notifyDataChanged();
viewBinding.recyclerViewSearchIssues.setAdapter(adapter);
viewBinding.noData.setVisibility(View.VISIBLE);
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
private void loadMore(String searchKeyword, int resultLimit, int page) {
viewBinding.progressBar.setVisibility(View.VISIBLE);
Call<List<Issues>> call = RetrofitClient.getApiInterface(context)
.queryIssues(((BaseActivity) requireActivity()).getAccount().getAuthorization(), searchKeyword, "issues", "open", resultLimit, page);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if(response.isSuccessful()) {
assert response.body() != null;
List<Issues> result = response.body();
if(result.size() > 0) {
pageSize = result.size();
dataList.addAll(result);
}
else {
SnackBar.info(context, viewBinding.getRoot(), getString(R.string.noMoreData));
adapter.setMoreDataAvailable(false);
}
adapter.notifyDataChanged();
viewBinding.progressBar.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());
}
viewBinding.progressBar.setVisibility(View.GONE);
});
}
}

View File

@ -0,0 +1,89 @@
package org.mian.gitnex.fragments;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.adapters.ExploreIssuesAdapter;
import org.mian.gitnex.databinding.FragmentIssuesBinding;
import org.mian.gitnex.viewmodels.IssuesViewModel;
/**
* @author M M Arif
*/
public class MyIssuesFragment extends Fragment {
private FragmentIssuesBinding fragmentIssuesBinding;
private ExploreIssuesAdapter adapter;
private int page = 1;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
fragmentIssuesBinding = FragmentIssuesBinding.inflate(inflater, container, false);
fragmentIssuesBinding.recyclerView.setHasFixedSize(true);
fragmentIssuesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(fragmentIssuesBinding.recyclerView.getContext(),
DividerItemDecoration.VERTICAL);
fragmentIssuesBinding.recyclerView.addItemDecoration(dividerItemDecoration);
fragmentIssuesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
fragmentIssuesBinding.pullToRefresh.setRefreshing(false);
IssuesViewModel.loadIssuesList(((BaseActivity) requireActivity()).getAccount().getAuthorization(), null, "issues", true, "open", getContext());
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
}, 50));
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization());
return fragmentIssuesBinding.getRoot();
};
private void fetchDataAsync(String instanceToken) {
IssuesViewModel issuesModel = new ViewModelProvider(this).get(IssuesViewModel.class);
issuesModel.getIssuesList(instanceToken, "", "issues", true, "open", getContext()).observe(getViewLifecycleOwner(), issuesListMain -> {
adapter = new ExploreIssuesAdapter(issuesListMain, getContext());
adapter.setLoadMoreListener(new ExploreIssuesAdapter.OnLoadMoreListener() {
@Override
public void onLoadMore() {
page += 1;
IssuesViewModel.loadMoreIssues(instanceToken, "", "issues", true, "open", page, getContext(), adapter);
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadFinished() {
fragmentIssuesBinding.progressBar.setVisibility(View.GONE);
}
});
if(adapter.getItemCount() > 0) {
fragmentIssuesBinding.recyclerView.setAdapter(adapter);
fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
}
else {
adapter.notifyDataChanged();
fragmentIssuesBinding.recyclerView.setAdapter(adapter);
fragmentIssuesBinding.noDataIssues.setVisibility(View.VISIBLE);
}
fragmentIssuesBinding.progressBar.setVisibility(View.GONE);
});
}
}

View File

@ -1,6 +1,5 @@
package org.mian.gitnex.fragments;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@ -9,15 +8,11 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.gitnex.tea4j.models.Releases;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.BaseActivity;
@ -35,13 +30,10 @@ import java.util.List;
public class ReleasesFragment extends Fragment {
private ProgressBar mProgressBar;
private ReleasesAdapter adapter;
private TagsAdapter tagsAdapter;
private RecyclerView mRecyclerView;
private TextView noDataReleases;
private RepositoryContext repository;
private FragmentReleasesBinding fragmentReleasesBinding;
private String releaseTag;
private int page = 1;
private int pageReleases = 1;
@ -66,31 +58,23 @@ public class ReleasesFragment extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
FragmentReleasesBinding fragmentReleasesBinding = FragmentReleasesBinding.inflate(inflater, container, false);
fragmentReleasesBinding = FragmentReleasesBinding.inflate(inflater, container, false);
noDataReleases = fragmentReleasesBinding.noDataReleases;
final SwipeRefreshLayout swipeRefresh = fragmentReleasesBinding.pullToRefresh;
mRecyclerView = fragmentReleasesBinding.recyclerView;
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
fragmentReleasesBinding.recyclerView.setHasFixedSize(true);
fragmentReleasesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(fragmentReleasesBinding.recyclerView.getContext(),
DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
fragmentReleasesBinding.recyclerView.addItemDecoration(dividerItemDecoration);
mProgressBar = fragmentReleasesBinding.progressBar;
fragmentReleasesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
swipeRefresh.setRefreshing(false);
fragmentReleasesBinding.pullToRefresh.setRefreshing(false);
if(repository.isReleasesViewTypeIsTag()) {
ReleasesViewModel.loadTagsList(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), getContext());
} else {
ReleasesViewModel.loadReleasesList(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), getContext());
}
mProgressBar.setVisibility(View.VISIBLE);
fragmentReleasesBinding.progressBar.setVisibility(View.VISIBLE);
}, 50));
@ -106,11 +90,10 @@ public class ReleasesFragment extends Fragment {
} else {
ReleasesViewModel.loadReleasesList(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), getContext());
}
mProgressBar.setVisibility(View.VISIBLE);
fragmentReleasesBinding.progressBar.setVisibility(View.VISIBLE);
});
return fragmentReleasesBinding.getRoot();
}
private void fetchDataAsync(String instanceToken, String owner, String repo) {
@ -126,31 +109,31 @@ public class ReleasesFragment extends Fragment {
public void onLoadMore() {
pageReleases += 1;
ReleasesViewModel.loadMoreReleases(instanceToken, owner, repo, pageReleases, getContext(), adapter);
mProgressBar.setVisibility(View.VISIBLE);
fragmentReleasesBinding.progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadFinished() {
mProgressBar.setVisibility(View.GONE);
fragmentReleasesBinding.progressBar.setVisibility(View.GONE);
}
});
if(adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
fragmentReleasesBinding.recyclerView.setAdapter(adapter);
if(releasesListMain != null && releaseTag != null) {
int index = getReleaseIndex(releaseTag, releasesListMain);
releaseTag = null;
if(index != -1) {
mRecyclerView.scrollToPosition(index);
fragmentReleasesBinding.recyclerView.scrollToPosition(index);
}
}
noDataReleases.setVisibility(View.GONE);
fragmentReleasesBinding.noDataReleases.setVisibility(View.GONE);
}
else {
adapter.notifyDataSetChanged();
mRecyclerView.setAdapter(adapter);
noDataReleases.setVisibility(View.VISIBLE);
adapter.notifyDataChanged();
fragmentReleasesBinding.recyclerView.setAdapter(adapter);
fragmentReleasesBinding.noDataReleases.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
fragmentReleasesBinding.progressBar.setVisibility(View.GONE);
}
});
@ -163,24 +146,24 @@ public class ReleasesFragment extends Fragment {
public void onLoadMore() {
page += 1;
ReleasesViewModel.loadMoreTags(instanceToken, owner, repo , page, getContext(), tagsAdapter);
mProgressBar.setVisibility(View.VISIBLE);
fragmentReleasesBinding.progressBar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadFinished() {
mProgressBar.setVisibility(View.GONE);
fragmentReleasesBinding.progressBar.setVisibility(View.GONE);
}
});
if(tagsAdapter.getItemCount() > 0) {
mRecyclerView.setAdapter(tagsAdapter);
noDataReleases.setVisibility(View.GONE);
fragmentReleasesBinding.recyclerView.setAdapter(tagsAdapter);
fragmentReleasesBinding.noDataReleases.setVisibility(View.GONE);
}
else {
tagsAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(tagsAdapter);
noDataReleases.setVisibility(View.VISIBLE);
tagsAdapter.notifyDataChanged();
fragmentReleasesBinding.recyclerView.setAdapter(tagsAdapter);
fragmentReleasesBinding.noDataReleases.setVisibility(View.VISIBLE);
}
mProgressBar.setVisibility(View.GONE);
fragmentReleasesBinding.progressBar.setVisibility(View.GONE);
}
});

View File

@ -1,7 +1,6 @@
package org.mian.gitnex.fragments;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
@ -17,11 +16,18 @@ import org.gitnex.tea4j.models.UserRepositories;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.activities.RepoForksActivity;
import org.mian.gitnex.activities.RepoStargazersActivity;
import org.mian.gitnex.activities.RepoWatchersActivity;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentRepoInfoBinding;
import org.mian.gitnex.helpers.*;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.contexts.RepositoryContext;
import java.util.Locale;
import retrofit2.Call;
@ -85,6 +91,8 @@ public class RepoInfoFragment extends Fragment {
binding.repoMetaWatchersFrame.setOnClickListener(metaWatchers -> ctx.startActivity(repository.getIntent(ctx, RepoWatchersActivity.class)));
binding.repoMetaForksFrame.setOnClickListener(metaForks -> ctx.startActivity(repository.getIntent(ctx, RepoForksActivity.class)));
binding.repoMetaPullRequestsFrame.setOnClickListener(metaPR -> ((RepoDetailActivity) requireActivity()).mViewPager.setCurrentItem(3));
return binding.getRoot();

View File

@ -0,0 +1,103 @@
package org.mian.gitnex.viewmodels;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.gitnex.tea4j.models.Issues;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.adapters.ExploreIssuesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Constants;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
*/
public class IssuesViewModel extends ViewModel {
private static MutableLiveData<List<Issues>> issuesList;
private static int resultLimit = Constants.resultLimitOldGiteaInstances;
public LiveData<List<Issues>> getIssuesList(String token, String searchKeyword, String type, Boolean created, String state, Context ctx) {
issuesList = new MutableLiveData<>();
// if gitea is 1.12 or higher use the new limit
if(((BaseActivity) ctx).getAccount().requiresVersion("1.12.0")) {
resultLimit = Constants.resultLimitNewGiteaInstances;
}
loadIssuesList(token, searchKeyword, type, created, state, ctx);
return issuesList;
}
public static void loadIssuesList(String token, String searchKeyword, String type, Boolean created, String state, Context ctx) {
Call<List<Issues>> call = RetrofitClient
.getApiInterface(ctx)
.queryIssues(token, searchKeyword, type, created, state, resultLimit, 1);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if (response.isSuccessful()) {
issuesList.postValue(response.body());
}
else {
Log.e("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
public static void loadMoreIssues(String token, String searchKeyword, String type, Boolean created, String state, int page, Context ctx, ExploreIssuesAdapter adapter) {
Call<List<Issues>> call = RetrofitClient
.getApiInterface(ctx)
.queryIssues(token, searchKeyword, type, created, state, resultLimit, page);
call.enqueue(new Callback<List<Issues>>() {
@Override
public void onResponse(@NonNull Call<List<Issues>> call, @NonNull Response<List<Issues>> response) {
if (response.isSuccessful()) {
List<Issues> list = issuesList.getValue();
assert list != null;
assert response.body() != null;
if(response.body().size() != 0) {
list.addAll(response.body());
adapter.updateList(list);
}
else {
adapter.setMoreDataAvailable(false);
}
}
else {
Log.e("onResponse", String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Issues>> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
}
});
}
}

View File

@ -11,17 +11,10 @@
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M12,8L12,12"
android:pathData="M11.75,11.75m-2.25,0a2.25,2.25 0,1 1,4.5 0a2.25,2.25 0,1 1,-4.5 0"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M12,16L12.01,16"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeWidth="73.9523"
android:fillColor="?attr/iconsColor"
android:strokeColor="#00000000"
android:strokeLineCap="round"/>
</vector>

View File

@ -4,14 +4,14 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M22,11.08V12a10,10 0,1 1,-5.93 -9.14"
android:pathData="M12,22c5.523,0 10,-4.477 10,-10S17.523,2 12,2 2,6.477 2,12s4.477,10 10,10z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="?attr/iconsColor"
android:strokeLineCap="round"/>
<path
android:pathData="M22,4l-10,10.01l-3,-3"
android:pathData="M9,12l2,2 4,-4"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"

View File

@ -62,7 +62,7 @@
android:text="@string/isClosed"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
app:drawableStartCompat="@drawable/ic_done" />
app:drawableStartCompat="@drawable/ic_issue_closed" />
</LinearLayout>

View File

@ -46,7 +46,7 @@
android:text="@string/isClosed"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
app:drawableStartCompat="@drawable/ic_done" />
app:drawableStartCompat="@drawable/ic_issue_closed" />
</LinearLayout>

View File

@ -84,12 +84,12 @@
android:orientation="vertical" >
<Button
android:id="@+id/cancel"
android:id="@+id/save"
android:layout_width="wrap_content"
android:layout_height="60dp"
style="?android:attr/button"
android:layout_alignParentStart="true"
android:text="@string/close"
android:text="@string/saveButton"
android:textColor="@color/colorWhite"
android:textSize="16sp" />

View File

@ -84,12 +84,12 @@
android:orientation="vertical" >
<Button
android:id="@+id/cancel"
android:id="@+id/save"
android:layout_width="wrap_content"
android:layout_height="60dp"
style="?android:attr/button"
android:layout_alignParentStart="true"
android:text="@string/close"
android:text="@string/saveButton"
android:textColor="@color/colorWhite"
android:textSize="16sp" />

View File

@ -23,6 +23,11 @@
android:icon="@drawable/ic_repo"
android:title="@string/navRepos" />
<item android:id="@+id/nav_my_issues"
android:icon="@drawable/ic_issue"
android:title="@string/navMyIssues"
android:visible="false" />
<item
android:id="@+id/nav_notifications"
android:icon="@drawable/ic_notifications"

View File

@ -59,6 +59,7 @@
<item>@string/pageTitleExplore</item>
<item>@string/titleDrafts</item>
<item>@string/pageTitleNotifications</item>
<item>@string/navMyIssues</item>
</string-array>
<string-array name="linkHandlerDefaultScreen">

View File

@ -28,6 +28,7 @@
<string name="navRate">Rate GitNex</string>
<string name="navLogout">Logout</string>
<string name="navAdministration">Administration</string>
<string name="navMyIssues">My Issues</string>
<!-- menu items -->
<!-- page titles -->