mirror of
https://codeberg.org/gitnex/GitNex
synced 2025-03-10 00:20:16 +01:00
Add support for unadopted repo management (#1125)
Support unadopted repos and allow to adopt and delete them. Only usable for admins. Co-authored-by: qwerty287 <ndev@web.de> Co-authored-by: M M Arif <mmarif@noreply.codeberg.org> Co-authored-by: M M Arif <mmarif@swatian.com> Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1125 Reviewed-by: M M Arif <mmarif@noreply.codeberg.org> Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org> Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
This commit is contained in:
parent
14488ea038
commit
c571e6cb95
@ -40,6 +40,9 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".activities.AdminGetUsersActivity"
|
android:name=".activities.AdminGetUsersActivity"
|
||||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" />
|
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" />
|
||||||
|
<activity
|
||||||
|
android:name=".activities.AdminUnadoptedReposActivity"
|
||||||
|
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.CreateReleaseActivity"
|
android:name=".activities.CreateReleaseActivity"
|
||||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" />
|
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation" />
|
||||||
|
@ -11,6 +11,7 @@ import androidx.recyclerview.widget.DividerItemDecoration;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import org.mian.gitnex.adapters.AdminCronTasksAdapter;
|
import org.mian.gitnex.adapters.AdminCronTasksAdapter;
|
||||||
import org.mian.gitnex.databinding.ActivityAdminCronTasksBinding;
|
import org.mian.gitnex.databinding.ActivityAdminCronTasksBinding;
|
||||||
|
import org.mian.gitnex.helpers.Constants;
|
||||||
import org.mian.gitnex.viewmodels.AdminCronTasksViewModel;
|
import org.mian.gitnex.viewmodels.AdminCronTasksViewModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,8 +26,8 @@ public class AdminCronTasksActivity extends BaseActivity {
|
|||||||
|
|
||||||
private ActivityAdminCronTasksBinding activityAdminCronTasksBinding;
|
private ActivityAdminCronTasksBinding activityAdminCronTasksBinding;
|
||||||
|
|
||||||
public static final int PAGE = 1;
|
private final int PAGE = 1;
|
||||||
public static final int LIMIT = 50;
|
private int resultLimit;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
@ -37,6 +38,7 @@ public class AdminCronTasksActivity extends BaseActivity {
|
|||||||
setContentView(activityAdminCronTasksBinding.getRoot());
|
setContentView(activityAdminCronTasksBinding.getRoot());
|
||||||
adminCronTasksViewModel = new ViewModelProvider(this).get(AdminCronTasksViewModel.class);
|
adminCronTasksViewModel = new ViewModelProvider(this).get(AdminCronTasksViewModel.class);
|
||||||
|
|
||||||
|
resultLimit = Constants.getCurrentResultLimit(ctx);
|
||||||
initCloseListener();
|
initCloseListener();
|
||||||
activityAdminCronTasksBinding.close.setOnClickListener(onClickListener);
|
activityAdminCronTasksBinding.close.setOnClickListener(onClickListener);
|
||||||
|
|
||||||
@ -52,8 +54,9 @@ public class AdminCronTasksActivity extends BaseActivity {
|
|||||||
|
|
||||||
activityAdminCronTasksBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
activityAdminCronTasksBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||||
|
|
||||||
|
activityAdminCronTasksBinding.progressBar.setVisibility(View.VISIBLE);
|
||||||
activityAdminCronTasksBinding.pullToRefresh.setRefreshing(false);
|
activityAdminCronTasksBinding.pullToRefresh.setRefreshing(false);
|
||||||
adminCronTasksViewModel.loadCronTasksList(ctx, PAGE, LIMIT);
|
adminCronTasksViewModel.loadCronTasksList(ctx, PAGE, resultLimit);
|
||||||
|
|
||||||
}, 500));
|
}, 500));
|
||||||
|
|
||||||
@ -62,26 +65,19 @@ public class AdminCronTasksActivity extends BaseActivity {
|
|||||||
|
|
||||||
private void fetchDataAsync(Context ctx) {
|
private void fetchDataAsync(Context ctx) {
|
||||||
|
|
||||||
AdminCronTasksViewModel cronTasksViewModel = new ViewModelProvider(this).get(AdminCronTasksViewModel.class);
|
adminCronTasksViewModel.getCronTasksList(ctx, PAGE, resultLimit).observe(this, cronTasksListMain -> {
|
||||||
|
|
||||||
cronTasksViewModel.getCronTasksList(ctx, PAGE, LIMIT).observe(this, cronTasksListMain -> {
|
|
||||||
|
|
||||||
adapter = new AdminCronTasksAdapter(cronTasksListMain);
|
adapter = new AdminCronTasksAdapter(cronTasksListMain);
|
||||||
|
|
||||||
if(adapter.getItemCount() > 0) {
|
if(adapter.getItemCount() > 0) {
|
||||||
|
|
||||||
activityAdminCronTasksBinding.recyclerView.setVisibility(View.VISIBLE);
|
|
||||||
activityAdminCronTasksBinding.recyclerView.setAdapter(adapter);
|
activityAdminCronTasksBinding.recyclerView.setAdapter(adapter);
|
||||||
activityAdminCronTasksBinding.noData.setVisibility(View.GONE);
|
activityAdminCronTasksBinding.noData.setVisibility(View.GONE);
|
||||||
|
activityAdminCronTasksBinding.progressBar.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
activityAdminCronTasksBinding.recyclerView.setVisibility(View.GONE);
|
|
||||||
activityAdminCronTasksBinding.noData.setVisibility(View.VISIBLE);
|
activityAdminCronTasksBinding.noData.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initCloseListener() {
|
private void initCloseListener() {
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
package org.mian.gitnex.activities;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.view.View;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import org.mian.gitnex.R;
|
||||||
|
import org.mian.gitnex.adapters.AdminUnadoptedReposAdapter;
|
||||||
|
import org.mian.gitnex.databinding.ActivityAdminCronTasksBinding;
|
||||||
|
import org.mian.gitnex.helpers.Constants;
|
||||||
|
import org.mian.gitnex.viewmodels.AdminUnadoptedReposViewModel;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author M M Arif
|
||||||
|
* @author qwerty287
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AdminUnadoptedReposActivity extends BaseActivity {
|
||||||
|
|
||||||
|
private AdminUnadoptedReposViewModel viewModel;
|
||||||
|
private View.OnClickListener onClickListener;
|
||||||
|
private AdminUnadoptedReposAdapter adapter;
|
||||||
|
|
||||||
|
private ActivityAdminCronTasksBinding binding;
|
||||||
|
|
||||||
|
private int PAGE = 1;
|
||||||
|
private int resultLimit;
|
||||||
|
private boolean reload = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
binding = ActivityAdminCronTasksBinding.inflate(getLayoutInflater());
|
||||||
|
setContentView(binding.getRoot());
|
||||||
|
viewModel = new ViewModelProvider(this).get(AdminUnadoptedReposViewModel.class);
|
||||||
|
|
||||||
|
resultLimit = Constants.getCurrentResultLimit(ctx);
|
||||||
|
initCloseListener();
|
||||||
|
binding.close.setOnClickListener(onClickListener);
|
||||||
|
|
||||||
|
Toolbar toolbar = binding.toolbar;
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
binding.toolbarTitle.setText(R.string.unadoptedRepos);
|
||||||
|
|
||||||
|
binding.recyclerView.setHasFixedSize(true);
|
||||||
|
binding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
|
||||||
|
|
||||||
|
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(binding.recyclerView.getContext(),
|
||||||
|
DividerItemDecoration.VERTICAL);
|
||||||
|
binding.recyclerView.addItemDecoration(dividerItemDecoration);
|
||||||
|
|
||||||
|
binding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||||
|
|
||||||
|
binding.pullToRefresh.setRefreshing(false);
|
||||||
|
PAGE = 1;
|
||||||
|
binding.progressBar.setVisibility(View.VISIBLE);
|
||||||
|
reload = true;
|
||||||
|
viewModel.loadRepos(ctx, PAGE, resultLimit, null);
|
||||||
|
|
||||||
|
}, 500));
|
||||||
|
|
||||||
|
adapter = new AdminUnadoptedReposAdapter(new ArrayList<>(), () -> {
|
||||||
|
PAGE = 1;
|
||||||
|
binding.progressBar.setVisibility(View.VISIBLE);
|
||||||
|
reload = true;
|
||||||
|
viewModel.loadRepos(ctx, PAGE, resultLimit, null);
|
||||||
|
}, () -> {
|
||||||
|
PAGE += 1;
|
||||||
|
binding.progressBar.setVisibility(View.VISIBLE);
|
||||||
|
viewModel.loadRepos(ctx, PAGE, resultLimit, null);
|
||||||
|
}, binding);
|
||||||
|
|
||||||
|
binding.recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
fetchDataAsync(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fetchDataAsync(Context ctx) {
|
||||||
|
|
||||||
|
AtomicInteger prevSize = new AtomicInteger();
|
||||||
|
|
||||||
|
viewModel.getUnadoptedRepos(ctx, PAGE, resultLimit, null).observe(this, list -> {
|
||||||
|
|
||||||
|
binding.progressBar.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
boolean hasMore = reload || list.size() > prevSize.get();
|
||||||
|
reload = false;
|
||||||
|
|
||||||
|
prevSize.set(list.size());
|
||||||
|
|
||||||
|
if(list.size() > 0) {
|
||||||
|
adapter.updateList(list);
|
||||||
|
adapter.setHasMore(hasMore);
|
||||||
|
binding.noData.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
binding.noData.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initCloseListener() {
|
||||||
|
onClickListener = view -> finish();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,201 @@
|
|||||||
|
package org.mian.gitnex.adapters;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import org.mian.gitnex.R;
|
||||||
|
import org.mian.gitnex.clients.RetrofitClient;
|
||||||
|
import org.mian.gitnex.databinding.ActivityAdminCronTasksBinding;
|
||||||
|
import org.mian.gitnex.helpers.AlertDialogs;
|
||||||
|
import org.mian.gitnex.helpers.Toasty;
|
||||||
|
import java.util.List;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author M M Arif
|
||||||
|
* @author qwerty287
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AdminUnadoptedReposAdapter extends RecyclerView.Adapter<AdminUnadoptedReposAdapter.UnadoptedViewHolder> {
|
||||||
|
|
||||||
|
private List<String> repos;
|
||||||
|
private final Runnable updateList;
|
||||||
|
private final Runnable loadMoreListener;
|
||||||
|
private boolean isLoading = false, hasMore = true;
|
||||||
|
private final ActivityAdminCronTasksBinding activityAdminCronTasksBinding;
|
||||||
|
|
||||||
|
class UnadoptedViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
||||||
|
private String repoName;
|
||||||
|
private final TextView name;
|
||||||
|
|
||||||
|
private UnadoptedViewHolder(View itemView) {
|
||||||
|
|
||||||
|
super(itemView);
|
||||||
|
Context ctx = itemView.getContext();
|
||||||
|
|
||||||
|
name = itemView.findViewById(R.id.repo_name);
|
||||||
|
|
||||||
|
itemView.setOnClickListener(taskInfo -> {
|
||||||
|
String[] repoSplit = repoName.split("/");
|
||||||
|
new AlertDialog.Builder(ctx)
|
||||||
|
.setTitle(repoName).setMessage(ctx.getString(R.string.unadoptedReposMessage, repoSplit[1], repoSplit[0]))
|
||||||
|
.setNeutralButton(R.string.close, null)
|
||||||
|
.setPositiveButton(R.string.menuDeleteText, ((dialog, which) -> delete(ctx, repoName)))
|
||||||
|
.setNegativeButton(R.string.adoptRepo, ((dialog, which) -> adopt(ctx, repoName, getBindingAdapterPosition()))).show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdminUnadoptedReposAdapter(List<String> list, Runnable updateList, Runnable loadMore, ActivityAdminCronTasksBinding activityAdminCronTasksBinding) {
|
||||||
|
this.repos = list;
|
||||||
|
this.updateList = updateList;
|
||||||
|
this.loadMoreListener = loadMore;
|
||||||
|
this.activityAdminCronTasksBinding = activityAdminCronTasksBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public UnadoptedViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
|
||||||
|
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_admin_unadopted_repos, parent, false);
|
||||||
|
return new UnadoptedViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull UnadoptedViewHolder holder, int position) {
|
||||||
|
if(position >= getItemCount() - 1 && hasMore && !isLoading && loadMoreListener != null) {
|
||||||
|
isLoading = true;
|
||||||
|
loadMoreListener.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
String currentItem = repos.get(position);
|
||||||
|
|
||||||
|
holder.repoName = currentItem;
|
||||||
|
holder.name.setText(currentItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAdapter(int position) {
|
||||||
|
repos.remove(position);
|
||||||
|
notifyItemRemoved(position);
|
||||||
|
notifyItemRangeChanged(position, repos.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void delete(final Context ctx, final String name) {
|
||||||
|
|
||||||
|
String[] repoSplit = name.split("/");
|
||||||
|
|
||||||
|
Call<Void> call = RetrofitClient
|
||||||
|
.getApiInterface(ctx)
|
||||||
|
.adminDeleteUnadoptedRepository(repoSplit[0], repoSplit[1]);
|
||||||
|
|
||||||
|
call.enqueue(new Callback<>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
|
||||||
|
|
||||||
|
switch(response.code()) {
|
||||||
|
|
||||||
|
case 204:
|
||||||
|
updateList.run();
|
||||||
|
Toasty.success(ctx, ctx.getString(R.string.repoDeletionSuccess));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 401:
|
||||||
|
AlertDialogs.authorizationTokenRevokedDialog(ctx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 403:
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 404:
|
||||||
|
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.genericError));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
|
||||||
|
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void adopt(final Context ctx, final String name, int position) {
|
||||||
|
|
||||||
|
String[] repoSplit = name.split("/");
|
||||||
|
|
||||||
|
Call<Void> call = RetrofitClient
|
||||||
|
.getApiInterface(ctx)
|
||||||
|
.adminAdoptRepository(repoSplit[0], repoSplit[1]);
|
||||||
|
|
||||||
|
call.enqueue(new Callback<>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call<Void> call, @NonNull retrofit2.Response<Void> response) {
|
||||||
|
|
||||||
|
switch(response.code()) {
|
||||||
|
|
||||||
|
case 204:
|
||||||
|
updateAdapter(position);
|
||||||
|
if(getItemCount() == 0) {
|
||||||
|
activityAdminCronTasksBinding.noData.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
Toasty.success(ctx, ctx.getString(R.string.repoAdopted, name));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 401:
|
||||||
|
AlertDialogs.authorizationTokenRevokedDialog(ctx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 403:
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 404:
|
||||||
|
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.genericError));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call<Void> call, @NonNull Throwable t) {
|
||||||
|
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return repos.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
public void updateList(List<String> list) {
|
||||||
|
this.repos = list;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHasMore(boolean hasMore) {
|
||||||
|
this.hasMore = hasMore;
|
||||||
|
isLoading = false;
|
||||||
|
}
|
||||||
|
}
|
@ -52,7 +52,7 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
|
|||||||
ImageView labelsOptionsMenu = itemView.findViewById(R.id.labelsOptionsMenu);
|
ImageView labelsOptionsMenu = itemView.findViewById(R.id.labelsOptionsMenu);
|
||||||
|
|
||||||
if((type.equals("repo") && !((RepoDetailActivity) itemView.getContext()).repository.getPermissions().isPush()) ||
|
if((type.equals("repo") && !((RepoDetailActivity) itemView.getContext()).repository.getPermissions().isPush()) ||
|
||||||
(type.equals("org") && !((OrganizationDetailActivity) itemView.getContext()).permissions.isIsOwner())) {
|
(type.equals("org") && (((OrganizationDetailActivity) itemView.getContext()).permissions == null || !((OrganizationDetailActivity) itemView.getContext()).permissions.isIsOwner()))) {
|
||||||
labelsOptionsMenu.setVisibility(View.GONE);
|
labelsOptionsMenu.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
labelsOptionsMenu.setOnClickListener(v -> {
|
labelsOptionsMenu.setOnClickListener(v -> {
|
||||||
|
@ -9,11 +9,9 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import org.gitnex.tea4j.v2.models.User;
|
import org.gitnex.tea4j.v2.models.User;
|
||||||
import org.mian.gitnex.R;
|
import org.mian.gitnex.R;
|
||||||
import org.mian.gitnex.actions.TeamActions;
|
|
||||||
import org.mian.gitnex.activities.BaseActivity;
|
import org.mian.gitnex.activities.BaseActivity;
|
||||||
import org.mian.gitnex.activities.ProfileActivity;
|
import org.mian.gitnex.activities.ProfileActivity;
|
||||||
import org.mian.gitnex.clients.PicassoService;
|
import org.mian.gitnex.clients.PicassoService;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package org.mian.gitnex.fragments;
|
package org.mian.gitnex.fragments;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -11,29 +10,30 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import org.mian.gitnex.activities.AdminCronTasksActivity;
|
import org.mian.gitnex.activities.AdminCronTasksActivity;
|
||||||
import org.mian.gitnex.activities.AdminGetUsersActivity;
|
import org.mian.gitnex.activities.AdminGetUsersActivity;
|
||||||
|
import org.mian.gitnex.activities.AdminUnadoptedReposActivity;
|
||||||
import org.mian.gitnex.activities.BaseActivity;
|
import org.mian.gitnex.activities.BaseActivity;
|
||||||
import org.mian.gitnex.databinding.FragmentAdministrationBinding;
|
import org.mian.gitnex.databinding.FragmentAdministrationBinding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Author M M Arif
|
* @author M M Arif
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AdministrationFragment extends Fragment {
|
public class AdministrationFragment extends Fragment {
|
||||||
|
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
|
||||||
Context ctx = getContext();
|
|
||||||
FragmentAdministrationBinding fragmentAdministrationBinding = FragmentAdministrationBinding.inflate(inflater, container, false);
|
FragmentAdministrationBinding fragmentAdministrationBinding = FragmentAdministrationBinding.inflate(inflater, container, false);
|
||||||
|
|
||||||
fragmentAdministrationBinding.adminUsers.setOnClickListener(v1 -> startActivity(new Intent(getContext(), AdminGetUsersActivity.class)));
|
fragmentAdministrationBinding.systemUsersFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), AdminGetUsersActivity.class)));
|
||||||
|
|
||||||
// if gitea version is greater/equal(1.13.0) than user installed version (installed.higherOrEqual(compareVer))
|
// if gitea version is greater/equal(1.13.0) than user installed version (installed.higherOrEqual(compareVer))
|
||||||
if(((BaseActivity) requireActivity()).getAccount().requiresVersion("1.13.0")) {
|
if(((BaseActivity) requireActivity()).getAccount().requiresVersion("1.13.0")) {
|
||||||
|
|
||||||
fragmentAdministrationBinding.adminCron.setVisibility(View.VISIBLE);
|
fragmentAdministrationBinding.adminCronFrame.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fragmentAdministrationBinding.adminCron.setOnClickListener(v1 -> startActivity(new Intent(getContext(), AdminCronTasksActivity.class)));
|
fragmentAdministrationBinding.adminCronFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), AdminCronTasksActivity.class)));
|
||||||
|
fragmentAdministrationBinding.unadoptedReposFrame.setOnClickListener(v1 -> startActivity(new Intent(getContext(), AdminUnadoptedReposActivity.class)));
|
||||||
|
|
||||||
String action = requireActivity().getIntent().getStringExtra("giteaAdminAction");
|
String action = requireActivity().getIntent().getStringExtra("giteaAdminAction");
|
||||||
if(action != null) {
|
if(action != null) {
|
||||||
|
@ -45,7 +45,11 @@ import java.util.Objects;
|
|||||||
import javax.net.ssl.HttpsURLConnection;
|
import javax.net.ssl.HttpsURLConnection;
|
||||||
import javax.net.ssl.SSLContext;
|
import javax.net.ssl.SSLContext;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import okhttp3.*;
|
import okhttp3.Call;
|
||||||
|
import okhttp3.Callback;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author M M Arif
|
* @author M M Arif
|
||||||
|
@ -5,12 +5,9 @@ import android.content.SharedPreferences;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Bitmap.CompressFormat;
|
import android.graphics.Bitmap.CompressFormat;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.text.TextUtils;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class TinyDB {
|
public class TinyDB {
|
||||||
|
@ -0,0 +1,78 @@
|
|||||||
|
package org.mian.gitnex.viewmodels;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
import androidx.lifecycle.ViewModel;
|
||||||
|
import org.mian.gitnex.R;
|
||||||
|
import org.mian.gitnex.clients.RetrofitClient;
|
||||||
|
import org.mian.gitnex.helpers.AlertDialogs;
|
||||||
|
import org.mian.gitnex.helpers.Toasty;
|
||||||
|
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
|
||||||
|
* @author qwerty287
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AdminUnadoptedReposViewModel extends ViewModel {
|
||||||
|
|
||||||
|
private MutableLiveData<List<String>> tasksList;
|
||||||
|
|
||||||
|
public LiveData<List<String>> getUnadoptedRepos(Context ctx, int page, int limit, String query) {
|
||||||
|
|
||||||
|
tasksList = new MutableLiveData<>();
|
||||||
|
loadRepos(ctx, page, limit, query);
|
||||||
|
|
||||||
|
return tasksList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadRepos(final Context ctx, final int page, int limit, String query) {
|
||||||
|
|
||||||
|
Call<List<String>> call = RetrofitClient
|
||||||
|
.getApiInterface(ctx)
|
||||||
|
.adminUnadoptedList(page, limit, query);
|
||||||
|
|
||||||
|
call.enqueue(new Callback<>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(@NonNull Call<List<String>> call, @NonNull Response<List<String>> response) {
|
||||||
|
|
||||||
|
if(response.isSuccessful()) {
|
||||||
|
if(page <= 1 || tasksList.getValue() == null) {
|
||||||
|
tasksList.postValue(response.body());
|
||||||
|
} else {
|
||||||
|
List<String> repos = new ArrayList<>(Objects.requireNonNull(tasksList.getValue()));
|
||||||
|
assert response.body() != null;
|
||||||
|
repos.addAll(response.body());
|
||||||
|
tasksList.postValue(repos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(response.code() == 401) {
|
||||||
|
AlertDialogs.authorizationTokenRevokedDialog(ctx);
|
||||||
|
}
|
||||||
|
else if(response.code() == 403) {
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
|
||||||
|
}
|
||||||
|
else if(response.code() == 404) {
|
||||||
|
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.genericError));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Call<List<String>> call, @NonNull Throwable t) {
|
||||||
|
|
||||||
|
Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
@ -47,10 +47,21 @@
|
|||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||||
|
android:id="@+id/progress_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="visible"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:layout_below="@+id/appbar"
|
||||||
|
style="@style/Widget.MaterialComponents.LinearProgressIndicator"
|
||||||
|
app:indicatorColor="?attr/progressIndicatorColor" />
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/pullToRefresh"
|
android:id="@+id/pullToRefresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_below="@+id/progress_bar">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
@ -70,6 +81,6 @@
|
|||||||
android:text="@string/noDataFound"
|
android:text="@string/noDataFound"
|
||||||
android:textColor="?attr/primaryTextColor"
|
android:textColor="?attr/primaryTextColor"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:visibility="visible" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</LinearLayout>
|
</RelativeLayout>
|
||||||
|
@ -11,21 +11,51 @@
|
|||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:orientation="vertical"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/systemUsersFrame"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/generalImgContentText"
|
||||||
|
app:srcCompat="@drawable/ic_people" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/adminUsers"
|
android:id="@+id/adminUsers"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
android:text="@string/adminUsers"
|
android:text="@string/adminUsers"
|
||||||
android:drawablePadding="32dp"
|
|
||||||
android:textColor="?attr/primaryTextColor"
|
android:textColor="?attr/primaryTextColor"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp" />
|
||||||
android:padding="16dp"
|
|
||||||
android:background="?android:attr/selectableItemBackground"
|
</LinearLayout>
|
||||||
app:drawableStartCompat="@drawable/ic_people" />
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:srcCompat="@drawable/ic_chevron_right"
|
||||||
|
android:contentDescription="@string/generalImgContentText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -33,19 +63,96 @@
|
|||||||
android:id="@+id/divider"
|
android:id="@+id/divider"
|
||||||
android:background="?attr/dividerColor" />
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/adminCronFrame"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/generalImgContentText"
|
||||||
|
app:srcCompat="@drawable/ic_tasks" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/adminCron"
|
android:id="@+id/adminCron"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_vertical"
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
android:text="@string/adminCron"
|
android:text="@string/adminCron"
|
||||||
android:drawablePadding="32dp"
|
|
||||||
android:textColor="?attr/primaryTextColor"
|
android:textColor="?attr/primaryTextColor"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp" />
|
||||||
android:padding="16dp"
|
|
||||||
android:visibility="gone"
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:srcCompat="@drawable/ic_chevron_right"
|
||||||
|
android:contentDescription="@string/generalImgContentText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?attr/dividerColor" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/unadoptedReposFrame"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:attr/selectableItemBackground"
|
android:background="?android:attr/selectableItemBackground"
|
||||||
app:drawableStartCompat="@drawable/ic_tasks" />
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/generalImgContentText"
|
||||||
|
app:srcCompat="@drawable/ic_directory" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/unadoptedRepos"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="12dp"
|
||||||
|
android:paddingEnd="12dp"
|
||||||
|
android:text="@string/unadoptedRepos"
|
||||||
|
android:textColor="?attr/primaryTextColor"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:srcCompat="@drawable/ic_chevron_right"
|
||||||
|
android:contentDescription="@string/generalImgContentText" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
17
app/src/main/res/layout/list_admin_unadopted_repos.xml
Normal file
17
app/src/main/res/layout/list_admin_unadopted_repos.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:background="?android:attr/selectableItemBackground" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/repo_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="5dp"
|
||||||
|
android:textColor="?attr/primaryTextColor"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -762,4 +762,8 @@
|
|||||||
<string name="followSystem">Follow system (Light/Dark)</string>
|
<string name="followSystem">Follow system (Light/Dark)</string>
|
||||||
<string name="followSystemBlack">Follow system (Light/Pitch Black)</string>
|
<string name="followSystemBlack">Follow system (Light/Pitch Black)</string>
|
||||||
<string name="repoForkOf">Fork of: %s</string>
|
<string name="repoForkOf">Fork of: %s</string>
|
||||||
|
<string name="adoptRepo">Adopt</string>
|
||||||
|
<string name="repoAdopted">Adopted repository %s</string>
|
||||||
|
<string name="unadoptedRepos">Unadopted Repositories</string>
|
||||||
|
<string name="unadoptedReposMessage">- Adopt will add repository %s to organization/user %s.\n- Delete will remove it from the system.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -247,6 +247,7 @@
|
|||||||
|
|
||||||
<style name="NegativeButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
<style name="NegativeButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
||||||
<item name="android:textColor">@color/darkGreen</item>
|
<item name="android:textColor">@color/darkGreen</item>
|
||||||
|
<item name="android:layout_marginEnd">16dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="PositiveButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
<style name="PositiveButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
||||||
@ -309,6 +310,7 @@
|
|||||||
|
|
||||||
<style name="RetroNegativeButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
<style name="RetroNegativeButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
||||||
<item name="android:textColor">@color/retroThemeTextColor</item>
|
<item name="android:textColor">@color/retroThemeTextColor</item>
|
||||||
|
<item name="android:layout_marginEnd">16dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="RetroPositiveButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
<style name="RetroPositiveButtonStyle" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user