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..6c94222c --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/activities/AddNewTeamRepoActivity.java @@ -0,0 +1,108 @@ +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.Constants; +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 int resultLimit; + + private long teamId; + private String teamName; + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + + addNewTeamRepositoryBinding = AddNewTeamRepositoryBinding.inflate(getLayoutInflater()); + setContentView(addNewTeamRepositoryBinding.getRoot()); + + resultLimit = Constants.getCurrentResultLimit(ctx); + 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, resultLimit); + + 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/FileViewActivity.java b/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java index dff14156..8b47f68d 100644 --- a/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/FileViewActivity.java @@ -48,6 +48,7 @@ public class FileViewActivity extends BaseActivity implements BottomSheetListene private ContentsResponse file; private RepositoryContext repository; private boolean renderMd = false; + private boolean processable = false; public ActivityResultLauncher editFileLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> { @@ -108,8 +109,6 @@ public class FileViewActivity extends BaseActivity implements BottomSheetListene runOnUiThread(() -> binding.progressBar.setVisibility(View.GONE)); String fileExtension = FilenameUtils.getExtension(filename); - boolean processable = false; - switch(AppUtil.getFileType(fileExtension)) { case IMAGE: @@ -246,7 +245,9 @@ public class FileViewActivity extends BaseActivity implements BottomSheetListene } else if(id == R.id.genericMenu) { BottomSheetFileViewerFragment bottomSheet = new BottomSheetFileViewerFragment(); - bottomSheet.setArguments(repository.getBundle()); + Bundle opts = repository.getBundle(); + opts.putBoolean("editable", processable); + bottomSheet.setArguments(opts); bottomSheet.show(getSupportFragmentManager(), "fileViewerBottomSheet"); return true; diff --git a/app/src/main/java/org/mian/gitnex/activities/OrganizationDetailActivity.java b/app/src/main/java/org/mian/gitnex/activities/OrganizationDetailActivity.java index 255b1a12..d257a4f4 100644 --- a/app/src/main/java/org/mian/gitnex/activities/OrganizationDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/OrganizationDetailActivity.java @@ -17,6 +17,7 @@ import androidx.fragment.app.FragmentPagerAdapter; import androidx.viewpager.widget.ViewPager; import com.google.android.material.tabs.TabLayout; import org.gitnex.tea4j.v2.models.OrganizationPermissions; +import org.jetbrains.annotations.NotNull; import org.mian.gitnex.R; import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.fragments.BottomSheetOrganizationFragment; @@ -40,6 +41,8 @@ import retrofit2.Response; public class OrganizationDetailActivity extends BaseActivity implements BottomSheetListener { public OrganizationPermissions permissions; + private String orgName; + private boolean isMember = false; @Override public void onCreate(Bundle savedInstanceState) { @@ -48,89 +51,118 @@ public class OrganizationDetailActivity extends BaseActivity implements BottomSh setContentView(R.layout.activity_org_detail); - String orgName = getIntent().getStringExtra("orgName"); + orgName = getIntent().getStringExtra("orgName"); Toolbar toolbar = findViewById(R.id.toolbar); - TextView toolbarTitle = findViewById(R.id.toolbar_title); setSupportActionBar(toolbar); Objects.requireNonNull(getSupportActionBar()).setTitle(orgName); getSupportActionBar().setDisplayHomeAsUpEnabled(true); - OrganizationDetailActivity.SectionsPagerAdapter mSectionsPagerAdapter = new OrganizationDetailActivity.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(ctx.getAssets(), "fonts/roboto.ttf"); - break; - case 2: - - myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/sourcecodeproregular.ttf"); - break; - default: - - myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/manroperegular.ttf"); - break; - } - - toolbarTitle.setTypeface(myTypeface); - toolbarTitle.setText(orgName); - - 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)); + checkIsMember(); if(getAccount().requiresVersion("1.16.0")) { RetrofitClient.getApiInterface(this) - .orgGetUserPermissions(getAccount().getAccount().getUserName(), orgName).enqueue(new Callback() { + .orgGetUserPermissions(getAccount().getAccount().getUserName(), orgName).enqueue(new Callback<>() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) { - if(response.isSuccessful()) { - permissions = response.body(); - } - else { - permissions = null; - } - } + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { - @Override - public void onFailure(@NonNull Call call, @NonNull Throwable t) { - permissions = null; - } - }); + if(response.isSuccessful()) { + permissions = response.body(); + } + else { + permissions = null; + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + permissions = null; + } + }); } else { permissions = null; } } + public void checkIsMember() { + RetrofitClient.getApiInterface(this).orgIsMember(orgName, getAccount().getAccount().getUserName()).enqueue(new Callback<>() { + + @Override + public void onResponse(@NotNull Call call, @NotNull Response response) { + isMember = response.code() != 404; + init(); + } + + @Override + public void onFailure(@NotNull Call call, @NotNull Throwable t) { + isMember = false; + init(); + } + }); + } + + public void init() { + OrganizationDetailActivity.SectionsPagerAdapter mSectionsPagerAdapter = new OrganizationDetailActivity.SectionsPagerAdapter(getSupportFragmentManager()); + + ViewPager mViewPager = findViewById(R.id.container); + mViewPager.setVisibility(View.VISIBLE); + mViewPager.setAdapter(mSectionsPagerAdapter); + + TabLayout tabLayout = findViewById(R.id.tabs); + tabLayout.setVisibility(View.VISIBLE); + + if(!isMember) { + tabLayout.removeTabAt(3); + } + + Typeface myTypeface; + + switch(tinyDB.getInt("customFontId", -1)) { + + case 0: + + myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/roboto.ttf"); + break; + case 2: + + myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/sourcecodeproregular.ttf"); + break; + default: + + myTypeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/manroperegular.ttf"); + break; + } + + TextView toolbarTitle = findViewById(R.id.toolbar_title); + + toolbarTitle.setTypeface(myTypeface); + toolbarTitle.setText(orgName); + + 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)); + } @Override public boolean onCreateOptionsMenu(Menu menu) { @@ -226,19 +258,29 @@ public class OrganizationDetailActivity extends BaseActivity implements BottomSh case 2: // labels return OrganizationLabelsFragment.newInstance(orgName); - case 3: // teams + case 3: // teams / members - return TeamsByOrgFragment.newInstance(orgName, permissions); + if(isMember) { + return TeamsByOrgFragment.newInstance(orgName, permissions); + } else { + return MembersByOrgFragment.newInstance(orgName); + } case 4: // members - return MembersByOrgFragment.newInstance(orgName); + if(isMember) { + return MembersByOrgFragment.newInstance(orgName); + } } return fragment; } @Override public int getCount() { - return 5; + if(isMember) { + return 5; + } else { + return 4; + } } } } 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/BottomSheetFileViewerFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java index 99fd42e0..390228b2 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetFileViewerFragment.java @@ -30,6 +30,8 @@ public class BottomSheetFileViewerFragment extends BottomSheetDialogFragment { if(!repository.getPermissions().isPush()) { bottomSheetFileViewerBinding.deleteFile.setVisibility(View.GONE); bottomSheetFileViewerBinding.editFile.setVisibility(View.GONE); + } else if(!requireArguments().getBoolean("editable")) { + bottomSheetFileViewerBinding.editFile.setVisibility(View.GONE); } bottomSheetFileViewerBinding.downloadFile.setOnClickListener(v1 -> { 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/BottomSheetSingleIssueFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSingleIssueFragment.java index 6f81d1b0..21445715 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSingleIssueFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetSingleIssueFragment.java @@ -251,6 +251,10 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment { binding.bottomSheetHeaderFrame.setVisibility(View.GONE); binding.issuePrDivider.setVisibility(View.GONE); } + else if(!canPush) { + binding.addRemoveAssignees.setVisibility(View.GONE); + binding.editLabels.setVisibility(View.GONE); + } return binding.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..5611800f --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/OrganizationTeamInfoReposFragment.java @@ -0,0 +1,159 @@ +package org.mian.gitnex.fragments; + +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.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 { + + private RepositoriesViewModel repositoriesViewModel; + public static boolean repoAdded = false; + + private FragmentRepositoriesBinding fragmentRepositoriesBinding; + private ReposListAdapter adapter; + private int page = 1; + private int resultLimit; + + 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); + + resultLimit = Constants.getCurrentResultLimit(getContext()); + setHasOptionsMenu(true); + team = (Team) requireArguments().getSerializable("team"); + + repositoriesViewModel = new ViewModelProvider(this).get(RepositoriesViewModel.class); + + 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.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 8486e8c3..f3722d65 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/RepositoriesByOrgFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/RepositoriesByOrgFragment.java @@ -79,6 +79,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 1823b63a..b5a2d7f6 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java +++ b/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java @@ -105,6 +105,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 2e14b8cc..7d6bf805 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/activity_org_detail.xml b/app/src/main/res/layout/activity_org_detail.xml index 4c338d50..db7d7d61 100644 --- a/app/src/main/res/layout/activity_org_detail.xml +++ b/app/src/main/res/layout/activity_org_detail.xml @@ -43,7 +43,8 @@ android:background="?attr/primaryBackgroundColor" app:tabIndicatorColor="?attr/pagerTabIndicatorColor" android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:visibility="gone"> + app:layout_behavior="@string/appbar_scrolling_view_behavior" + android:visibility="gone"/> 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..5729a102 --- /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 3af67cc0..223f6c40 100644 --- a/app/src/main/res/layout/bottom_sheet_organization_teams.xml +++ b/app/src/main/res/layout/bottom_sheet_organization_teams.xml @@ -45,6 +45,19 @@ android:padding="8dp" app:alignContent="stretch" > + + 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