From a05216e18a779101c1430e35ea034458079bd6d7 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Thu, 21 Apr 2022 23:02:59 +0200 Subject: [PATCH] Add support for team repos (#1113) * view team repos * add team repos * removing does not work due to missing APIs Closes #7 and replaces https://codeberg.org/gitnex/GitNex/pulls/701 Co-authored-by: qwerty287 Co-authored-by: M M Arif Co-authored-by: M M Arif Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1113 Reviewed-by: M M Arif Co-authored-by: qwerty287 Co-committed-by: qwerty287 --- app/src/main/AndroidManifest.xml | 3 + .../org/mian/gitnex/actions/TeamActions.java | 99 +++++++++++ .../activities/AddNewTeamRepoActivity.java | 105 ++++++++++++ .../OrganizationTeamInfoActivity.java | 26 ++- .../adapters/TeamRepositoriesAdapter.java | 157 +++++++++++++++++ .../BottomSheetOrganizationTeamsFragment.java | 9 + .../OrganizationTeamInfoReposFragment.java | 159 ++++++++++++++++++ .../fragments/RepositoriesByOrgFragment.java | 1 + .../org/mian/gitnex/helpers/AlertDialogs.java | 20 +++ .../viewmodels/RepositoriesViewModel.java | 6 + .../res/layout/add_new_team_repository.xml | 80 +++++++++ .../bottom_sheet_organization_teams.xml | 15 ++ app/src/main/res/values/strings.xml | 5 + 13 files changed, 680 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/mian/gitnex/activities/AddNewTeamRepoActivity.java create mode 100644 app/src/main/java/org/mian/gitnex/adapters/TeamRepositoriesAdapter.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/OrganizationTeamInfoReposFragment.java create mode 100644 app/src/main/res/layout/add_new_team_repository.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7d8d6002..2d24b0d0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -136,6 +136,9 @@ + diff --git a/app/src/main/java/org/mian/gitnex/actions/TeamActions.java b/app/src/main/java/org/mian/gitnex/actions/TeamActions.java index e74ad1f6..efdaf7ef 100644 --- a/app/src/main/java/org/mian/gitnex/actions/TeamActions.java +++ b/app/src/main/java/org/mian/gitnex/actions/TeamActions.java @@ -4,7 +4,9 @@ import android.content.Context; import androidx.annotation.NonNull; import org.mian.gitnex.R; import org.mian.gitnex.activities.AddNewTeamMemberActivity; +import org.mian.gitnex.activities.AddNewTeamRepoActivity; import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.fragments.OrganizationTeamInfoReposFragment; import org.mian.gitnex.helpers.AlertDialogs; import org.mian.gitnex.helpers.Toasty; import retrofit2.Call; @@ -110,4 +112,101 @@ public class TeamActions { } }); } + + public static void removeTeamRepo(final Context context, String orgName, int teamId, String repo) { + + Call call = RetrofitClient + .getApiInterface(context) + .orgRemoveTeamRepository((long) teamId, orgName, repo); + + call.enqueue(new Callback<>() { + + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + + if(response.isSuccessful()) { + + if(response.code() == 204) { + + OrganizationTeamInfoReposFragment.repoAdded = true; + Toasty.success(context, context.getString(R.string.repoRemovedMessage)); + ((AddNewTeamRepoActivity) context).finish(); + } + + } + else if(response.code() == 401) { + + AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), + context.getResources().getString(R.string.alertDialogTokenRevokedMessage), context.getResources().getString(R.string.cancelButton), + context.getResources().getString(R.string.navLogout)); + } + else if(response.code() == 403) { + + Toasty.error(context, context.getString(R.string.authorizeError)); + } + else if(response.code() == 404) { + + Toasty.warning(context, context.getString(R.string.apiNotFound)); + } + else { + + Toasty.error(context, context.getString(R.string.genericError)); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + Toasty.error(context, context.getResources().getString(R.string.genericServerResponseError)); + } + }); + } + + public static void addTeamRepo(final Context context, String orgName, int teamId, String repo) { + + Call call = RetrofitClient + .getApiInterface(context) + .orgAddTeamRepository((long) teamId, orgName, repo); + + call.enqueue(new Callback<>() { + + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + + if(response.isSuccessful()) { + + if(response.code() == 204) { + + OrganizationTeamInfoReposFragment.repoAdded = true; + Toasty.success(context, context.getString(R.string.repoAddedMessage)); + ((AddNewTeamRepoActivity) context).finish(); + } + } + else if(response.code() == 401) { + + AlertDialogs.authorizationTokenRevokedDialog(context, context.getResources().getString(R.string.alertDialogTokenRevokedTitle), + context.getResources().getString(R.string.alertDialogTokenRevokedMessage), context.getResources().getString(R.string.cancelButton), + context.getResources().getString(R.string.navLogout)); + } + else if(response.code() == 403) { + + Toasty.error(context, context.getString(R.string.authorizeError)); + } + else if(response.code() == 404) { + + Toasty.warning(context, context.getString(R.string.apiNotFound)); + } + else { + + Toasty.error(context, context.getString(R.string.genericError)); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + Toasty.error(context, context.getResources().getString(R.string.genericServerResponseError)); + } + }); + } } diff --git a/app/src/main/java/org/mian/gitnex/activities/AddNewTeamRepoActivity.java b/app/src/main/java/org/mian/gitnex/activities/AddNewTeamRepoActivity.java new file mode 100644 index 00000000..adff8405 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/activities/AddNewTeamRepoActivity.java @@ -0,0 +1,105 @@ +package org.mian.gitnex.activities; + +import android.os.Bundle; +import android.view.View; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import org.gitnex.tea4j.v2.models.Repository; +import org.mian.gitnex.R; +import org.mian.gitnex.adapters.TeamRepositoriesAdapter; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.databinding.AddNewTeamRepositoryBinding; +import org.mian.gitnex.helpers.Toasty; +import java.util.ArrayList; +import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Author M M Arif + */ + +public class AddNewTeamRepoActivity extends BaseActivity { + + private AddNewTeamRepositoryBinding addNewTeamRepositoryBinding; + private View.OnClickListener onClickListener; + private List dataList; + private TeamRepositoriesAdapter adapter; + + private long teamId; + private String teamName; + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + addNewTeamRepositoryBinding = AddNewTeamRepositoryBinding.inflate(getLayoutInflater()); + setContentView(addNewTeamRepositoryBinding.getRoot()); + + initCloseListener(); + addNewTeamRepositoryBinding.close.setOnClickListener(onClickListener); + + teamId = getIntent().getLongExtra("teamId", 0); + teamName = getIntent().getStringExtra("teamName"); + + addNewTeamRepositoryBinding.recyclerViewTeamRepos.setHasFixedSize(true); + addNewTeamRepositoryBinding.recyclerViewTeamRepos.setLayoutManager(new LinearLayoutManager(ctx)); + + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(addNewTeamRepositoryBinding.recyclerViewTeamRepos.getContext(), DividerItemDecoration.VERTICAL); + addNewTeamRepositoryBinding.recyclerViewTeamRepos.addItemDecoration(dividerItemDecoration); + + dataList = new ArrayList<>(); + + loadRepos(); + } + + public void loadRepos() { + + Call> call = RetrofitClient.getApiInterface(ctx).orgListRepos(getIntent().getStringExtra("orgName"), 1, 50); + + addNewTeamRepositoryBinding.progressBar.setVisibility(View.VISIBLE); + + call.enqueue(new Callback<>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.isSuccessful()) { + + assert response.body() != null; + if(response.body().size() > 0) { + + dataList.clear(); + dataList.addAll(response.body()); + + adapter = new TeamRepositoriesAdapter(dataList, ctx, Math.toIntExact(teamId), getIntent().getStringExtra("orgName"), teamName); + + addNewTeamRepositoryBinding.recyclerViewTeamRepos.setAdapter(adapter); + addNewTeamRepositoryBinding.noData.setVisibility(View.GONE); + } + else { + + addNewTeamRepositoryBinding.noData.setVisibility(View.VISIBLE); + } + + addNewTeamRepositoryBinding.progressBar.setVisibility(View.GONE); + } + else { + Toasty.error(ctx, getString(R.string.genericError)); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError)); + } + }); + } + + private void initCloseListener() { + onClickListener = view -> finish(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/activities/OrganizationTeamInfoActivity.java b/app/src/main/java/org/mian/gitnex/activities/OrganizationTeamInfoActivity.java index a9b7541c..2e87111a 100644 --- a/app/src/main/java/org/mian/gitnex/activities/OrganizationTeamInfoActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/OrganizationTeamInfoActivity.java @@ -19,6 +19,7 @@ import org.mian.gitnex.databinding.ActivityOrgTeamInfoBinding; import org.mian.gitnex.fragments.BottomSheetOrganizationTeamsFragment; import org.mian.gitnex.fragments.OrganizationTeamInfoMembersFragment; import org.mian.gitnex.fragments.OrganizationTeamInfoPermissionsFragment; +import org.mian.gitnex.fragments.OrganizationTeamInfoReposFragment; import org.mian.gitnex.structs.BottomSheetListener; /** @@ -50,14 +51,17 @@ public class OrganizationTeamInfoActivity extends BaseActivity implements Bottom } binding.close.setOnClickListener(view -> finish()); + binding.pager.setOffscreenPageLimit(1); binding.pager.setAdapter(new FragmentStateAdapter(getSupportFragmentManager(), getLifecycle()) { @NonNull @Override public Fragment createFragment(int position) { switch(position) { case 0: - return OrganizationTeamInfoMembersFragment.newInstance(team); + return OrganizationTeamInfoReposFragment.newInstance(team); case 1: + return OrganizationTeamInfoMembersFragment.newInstance(team); + case 2: return OrganizationTeamInfoPermissionsFragment.newInstance(team); } return null; @@ -65,20 +69,23 @@ public class OrganizationTeamInfoActivity extends BaseActivity implements Bottom @Override public int getItemCount() { - return 2; + return 3; } }); new TabLayoutMediator(binding.tabs, binding.pager, (tab, position) -> { - TextView textView = (TextView) LayoutInflater.from(ctx).inflate(R.layout.layout_tab_text, null); + TextView textView = (TextView) LayoutInflater.from(ctx).inflate(R.layout.layout_tab_text, findViewById(android.R.id.content), false); switch(position) { case 0: - textView.setText(R.string.orgTabMembers); + textView.setText(R.string.navRepos); break; case 1: - textView.setText(R.string.teamPermissions); + textView.setText(R.string.orgTabMembers); break; + case 2: + textView.setText(R.string.teamPermissions); + break; } tab.setCustomView(textView); @@ -105,6 +112,9 @@ public class OrganizationTeamInfoActivity extends BaseActivity implements Bottom } else if(id == R.id.genericMenu) { BottomSheetOrganizationTeamsFragment bottomSheet = new BottomSheetOrganizationTeamsFragment(); + Bundle args = new Bundle(); + args.putBoolean("showRepo", !team.isIncludesAllRepositories()); + bottomSheet.setArguments(args); bottomSheet.show(getSupportFragmentManager(), "orgTeamsBottomSheet"); return true; } @@ -119,6 +129,12 @@ public class OrganizationTeamInfoActivity extends BaseActivity implements Bottom Intent intent = new Intent(OrganizationTeamInfoActivity.this, AddNewTeamMemberActivity.class); intent.putExtra("teamId", team.getId()); startActivity(intent); + } else if("newRepo".equals(text)) { + Intent intent = new Intent(OrganizationTeamInfoActivity.this, AddNewTeamRepoActivity.class); + intent.putExtra("teamId", team.getId()); + intent.putExtra("teamName", team.getName()); + intent.putExtra("orgName", getIntent().getStringExtra("orgName")); + startActivity(intent); } } } diff --git a/app/src/main/java/org/mian/gitnex/adapters/TeamRepositoriesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/TeamRepositoriesAdapter.java new file mode 100644 index 00000000..172886e3 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/TeamRepositoriesAdapter.java @@ -0,0 +1,157 @@ +package org.mian.gitnex.adapters; + +import android.content.Context; +import android.graphics.Typeface; +import android.os.Handler; +import android.os.Looper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import com.amulyakhare.textdrawable.TextDrawable; +import com.amulyakhare.textdrawable.util.ColorGenerator; +import org.gitnex.tea4j.v2.models.Repository; +import org.mian.gitnex.R; +import org.mian.gitnex.clients.PicassoService; +import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.RoundedTransformation; +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 TeamRepositoriesAdapter extends RecyclerView.Adapter { + + private final List reposList; + private final Context context; + private final int teamId; + private final String orgName; + private final String teamName; + private final List reposArr; + + public TeamRepositoriesAdapter(List dataList, Context ctx, int teamId, String orgName, String teamName) { + this.context = ctx; + this.reposList = dataList; + this.teamId = teamId; + this.orgName = orgName; + this.teamName = teamName; + reposArr = new ArrayList<>(); + } + + class TeamReposViewHolder extends RecyclerView.ViewHolder { + + private Repository repoInfo; + + private final ImageView repoAvatar; + private final TextView name; + private final ImageView addRepoButtonAdd; + + private TeamReposViewHolder(View itemView) { + + super(itemView); + repoAvatar = itemView.findViewById(R.id.userAvatar); + name = itemView.findViewById(R.id.userFullName); + itemView.findViewById(R.id.userName).setVisibility(View.GONE); + addRepoButtonAdd = itemView.findViewById(R.id.addCollaboratorButtonAdd); + ImageView addRepoButtonRemove = itemView.findViewById(R.id.addCollaboratorButtonRemove); + //addRepoButtonAdd.setVisibility(View.VISIBLE); + //addRepoButtonRemove.setVisibility(View.GONE); + + new Handler(Looper.getMainLooper()).postDelayed(TeamRepositoriesAdapter.this::getTeamRepos, 200); + + new Handler(Looper.getMainLooper()).postDelayed(() -> { + + if(reposArr.size() > 0) { + for(int i = 0; i < reposArr.size(); i++) { + if(!reposArr.get(i).getName().equals(repoInfo.getName())) { + addRepoButtonAdd.setVisibility(View.VISIBLE); + } + else { + addRepoButtonAdd.setVisibility(View.GONE); + } + } + } + else { + addRepoButtonAdd.setVisibility(View.VISIBLE); + } + }, 500); + + addRepoButtonAdd.setOnClickListener(v -> AlertDialogs.addRepoDialog(context, orgName, repoInfo.getName(), Integer.parseInt(String.valueOf(teamId)), teamName)); + + addRepoButtonRemove.setOnClickListener(v -> + AlertDialogs.removeRepoDialog(context, orgName, repoInfo.getName(), Integer.parseInt(String.valueOf(teamId)), teamName)); + } + + } + + @NonNull + @Override + public TeamRepositoriesAdapter.TeamReposViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_collaborators_search, parent, false); + return new TeamRepositoriesAdapter.TeamReposViewHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull final TeamRepositoriesAdapter.TeamReposViewHolder holder, int position) { + + Repository currentItem = reposList.get(position); + holder.repoInfo = currentItem; + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + + holder.name.setText(currentItem.getName()); + + TextDrawable drawable = TextDrawable.builder().beginConfig().useFont(Typeface.DEFAULT).fontSize(18).toUpperCase().width(28).height(28) + .endConfig().buildRoundRect(String.valueOf(currentItem.getFullName().charAt(0)), ColorGenerator.Companion.getMATERIAL().getColor(currentItem.getName()), 3); + + if(currentItem.getAvatarUrl() != null && !currentItem.getAvatarUrl().equals("")) { + PicassoService.getInstance(context).get().load(currentItem.getAvatarUrl()).placeholder(R.drawable.loader_animated) + .transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(holder.repoAvatar); + } + else { + holder.repoAvatar.setImageDrawable(drawable); + } + + } + + @Override + public int getItemCount() { + return reposList.size(); + } + + private void getTeamRepos() { + + if(getItemCount() > 0) { + Call> call = RetrofitClient + .getApiInterface(context) + .orgListTeamRepos((long) teamId, 1, 50); + + call.enqueue(new Callback<>() { + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if(response.code() == 200) { + + for(int i = 0; i < Objects.requireNonNull(response.body()).size(); i++) { + reposArr.addAll(response.body()); + } + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + } + }); + } + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetOrganizationTeamsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetOrganizationTeamsFragment.java index cc74434a..1748a4d5 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetOrganizationTeamsFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetOrganizationTeamsFragment.java @@ -33,6 +33,15 @@ public class BottomSheetOrganizationTeamsFragment extends BottomSheetDialogFragm }); + if(!requireArguments().getBoolean("showRepo")) { + bottomSheetOrganizationTeamsBinding.addRepo.setVisibility(View.GONE); + } + bottomSheetOrganizationTeamsBinding.addRepo.setOnClickListener(v1 -> { + bmListener.onButtonClicked("newRepo"); + dismiss(); + + }); + return bottomSheetOrganizationTeamsBinding.getRoot(); } diff --git a/app/src/main/java/org/mian/gitnex/fragments/OrganizationTeamInfoReposFragment.java b/app/src/main/java/org/mian/gitnex/fragments/OrganizationTeamInfoReposFragment.java new file mode 100644 index 00000000..4b4a8f1b --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/OrganizationTeamInfoReposFragment.java @@ -0,0 +1,159 @@ +package org.mian.gitnex.fragments; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +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 androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import org.gitnex.tea4j.v2.models.Team; +import org.mian.gitnex.R; +import org.mian.gitnex.activities.CreateRepoActivity; +import org.mian.gitnex.activities.MainActivity; +import org.mian.gitnex.adapters.ReposListAdapter; +import org.mian.gitnex.databinding.FragmentRepositoriesBinding; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.DividerItemDecorator; +import org.mian.gitnex.viewmodels.RepositoriesViewModel; + +/** + * @author M M Arif + */ + +public class OrganizationTeamInfoReposFragment extends Fragment { + + public static boolean repoAdded = false; + + private FragmentRepositoriesBinding fragmentRepositoriesBinding; + private ReposListAdapter adapter; + private int page = 1; + private final int resultLimit = Constants.resultLimitNewGiteaInstances; + + private Team team; + + public static OrganizationTeamInfoReposFragment newInstance(Team team) { + OrganizationTeamInfoReposFragment fragment = new OrganizationTeamInfoReposFragment(); + + Bundle bundle = new Bundle(); + bundle.putSerializable("team", team); + fragment.setArguments(bundle); + + return fragment; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + fragmentRepositoriesBinding = FragmentRepositoriesBinding.inflate(inflater, container, false); + + setHasOptionsMenu(true); + team = (Team) requireArguments().getSerializable("team"); + + fragmentRepositoriesBinding.addNewRepo.setVisibility(View.GONE); + + fragmentRepositoriesBinding.recyclerView.setHasFixedSize(true); + fragmentRepositoriesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + + RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(requireContext(), R.drawable.shape_list_divider)); + fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration); + + fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + + page = 1; + fragmentRepositoriesBinding.pullToRefresh.setRefreshing(false); + fetchDataAsync(); + fragmentRepositoriesBinding.progressBar.setVisibility(View.VISIBLE); + }, 50)); + + fetchDataAsync(); + + return fragmentRepositoriesBinding.getRoot(); + } + + private void fetchDataAsync() { + + RepositoriesViewModel reposModel = new ViewModelProvider(this).get(RepositoriesViewModel.class); + + reposModel.getRepositories(page, resultLimit, String.valueOf(team.getId()), "team", null, getContext()).observe(getViewLifecycleOwner(), reposListMain -> { + + adapter = new ReposListAdapter(reposListMain, getContext()); + adapter.setLoadMoreListener(new ReposListAdapter.OnLoadMoreListener() { + + @Override + public void onLoadMore() { + + page += 1; + RepositoriesViewModel.loadMoreRepos(page, resultLimit, String.valueOf(team.getId()), "team", null, getContext(), adapter); + fragmentRepositoriesBinding.progressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onLoadFinished() { + + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + } + }); + + if(adapter.getItemCount() > 0) { + fragmentRepositoriesBinding.recyclerView.setAdapter(adapter); + fragmentRepositoriesBinding.noData.setVisibility(View.GONE); + } + else { + adapter.notifyDataChanged(); + fragmentRepositoriesBinding.recyclerView.setAdapter(adapter); + fragmentRepositoriesBinding.noData.setVisibility(View.VISIBLE); + } + + fragmentRepositoriesBinding.progressBar.setVisibility(View.GONE); + }); + } + + @Override + public void onResume() { + super.onResume(); + + if(repoAdded) { + page = 1; + fetchDataAsync(); + MainActivity.repoCreated = false; + } + } + + @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) { + if(fragmentRepositoriesBinding.recyclerView.getAdapter() != null) { + adapter.getFilter().filter(newText); + } + return false; + } + }); + } +} + diff --git a/app/src/main/java/org/mian/gitnex/fragments/RepositoriesByOrgFragment.java b/app/src/main/java/org/mian/gitnex/fragments/RepositoriesByOrgFragment.java index 0a243c48..d4b2ad7b 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/RepositoriesByOrgFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/RepositoriesByOrgFragment.java @@ -76,6 +76,7 @@ public class RepositoriesByOrgFragment extends Fragment { fragmentRepositoriesBinding.progressBar.setVisibility(View.VISIBLE); }, 50)); + page = 1; fetchDataAsync(); return fragmentRepositoriesBinding.getRoot(); diff --git a/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java b/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java index 833acc65..ace9f449 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java +++ b/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java @@ -138,6 +138,26 @@ public class AlertDialogs { } + public static void addRepoDialog(final Context context, final String orgName, String repo, int teamId, String teamName) { + + new AlertDialog.Builder(context) + .setTitle(context.getResources().getString(R.string.addTeamMemberTitle) + repo) + .setMessage(context.getResources().getString(R.string.repoAddToTeamMessage, repo, orgName, teamName)) + .setPositiveButton(context.getResources().getString(R.string.addButton), (dialog, whichButton) -> TeamActions.addTeamRepo(context, orgName, teamId, repo)) + .setNeutralButton(context.getResources().getString(R.string.cancelButton), null).show(); + + } + + public static void removeRepoDialog(final Context context, final String orgName, String repo, int teamId, String teamName) { + + new AlertDialog.Builder(context) + .setTitle(context.getResources().getString(R.string.removeTeamMemberTitle) + repo) + .setMessage(context.getResources().getString(R.string.repoRemoveTeamMessage, repo, teamName)) + .setPositiveButton(context.getResources().getString(R.string.removeButton), (dialog, whichButton) -> TeamActions.removeTeamRepo(context, orgName, teamId, repo)) + .setNeutralButton(context.getResources().getString(R.string.cancelButton), null).show(); + + } + public static void selectPullUpdateStrategy(Context context, String repoOwner, String repo, String issueNumber) { Dialog dialog = new Dialog(context, R.style.ThemeOverlay_MaterialComponents_Dialog_Alert); diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/RepositoriesViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/RepositoriesViewModel.java index ca30b1e1..ee80ba16 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/RepositoriesViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/RepositoriesViewModel.java @@ -45,6 +45,9 @@ public class RepositoriesViewModel extends ViewModel { case "org": call = RetrofitClient.getApiInterface(ctx).orgListRepos(orgName, page, resultLimit); break; + case "team": + call = RetrofitClient.getApiInterface(ctx).orgListTeamRepos(Long.valueOf(userLogin), page, resultLimit); + break; default: call = RetrofitClient.getApiInterface(ctx).userCurrentListRepos(page, resultLimit); break; @@ -88,6 +91,9 @@ public class RepositoriesViewModel extends ViewModel { case "org": call = RetrofitClient.getApiInterface(ctx).orgListRepos(orgName, page, resultLimit); break; + case "team": + call = RetrofitClient.getApiInterface(ctx).orgListTeamRepos(Long.valueOf(userLogin), page, resultLimit); + break; default: call = RetrofitClient.getApiInterface(ctx).userCurrentListRepos(page, resultLimit); break; diff --git a/app/src/main/res/layout/add_new_team_repository.xml b/app/src/main/res/layout/add_new_team_repository.xml new file mode 100644 index 00000000..7cb53656 --- /dev/null +++ b/app/src/main/res/layout/add_new_team_repository.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/bottom_sheet_organization_teams.xml b/app/src/main/res/layout/bottom_sheet_organization_teams.xml index ea60c3ee..a3d80fdd 100644 --- a/app/src/main/res/layout/bottom_sheet_organization_teams.xml +++ b/app/src/main/res/layout/bottom_sheet_organization_teams.xml @@ -33,6 +33,21 @@ android:textSize="16sp" app:drawableStartCompat="@drawable/ic_person_add" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7092415a..bc991ddf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -286,12 +286,17 @@ Org members Organization team members Add / Remove New Member + Add Repository Remove\u0020 Add\u0020 Do you want to add this user to the team? Do you want to remove this user from the team? Member added to the team successfully Member removed from the team successfully + Repository added to the team successfully + Repository removed from the team successfully + Add repository %s to organization %s team %s + Remove repository %s from team %s