diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ac021f42..f3b4b077 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -40,6 +40,9 @@
+
diff --git a/app/src/main/java/org/mian/gitnex/activities/AdminCronTasksActivity.java b/app/src/main/java/org/mian/gitnex/activities/AdminCronTasksActivity.java
index 267ab464..ecbdfa65 100644
--- a/app/src/main/java/org/mian/gitnex/activities/AdminCronTasksActivity.java
+++ b/app/src/main/java/org/mian/gitnex/activities/AdminCronTasksActivity.java
@@ -11,6 +11,7 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.mian.gitnex.adapters.AdminCronTasksAdapter;
import org.mian.gitnex.databinding.ActivityAdminCronTasksBinding;
+import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.viewmodels.AdminCronTasksViewModel;
/**
@@ -25,8 +26,8 @@ public class AdminCronTasksActivity extends BaseActivity {
private ActivityAdminCronTasksBinding activityAdminCronTasksBinding;
- public static final int PAGE = 1;
- public static final int LIMIT = 50;
+ private final int PAGE = 1;
+ private int resultLimit;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -37,6 +38,7 @@ public class AdminCronTasksActivity extends BaseActivity {
setContentView(activityAdminCronTasksBinding.getRoot());
adminCronTasksViewModel = new ViewModelProvider(this).get(AdminCronTasksViewModel.class);
+ resultLimit = Constants.getCurrentResultLimit(ctx);
initCloseListener();
activityAdminCronTasksBinding.close.setOnClickListener(onClickListener);
@@ -52,8 +54,9 @@ public class AdminCronTasksActivity extends BaseActivity {
activityAdminCronTasksBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
+ activityAdminCronTasksBinding.progressBar.setVisibility(View.VISIBLE);
activityAdminCronTasksBinding.pullToRefresh.setRefreshing(false);
- adminCronTasksViewModel.loadCronTasksList(ctx, PAGE, LIMIT);
+ adminCronTasksViewModel.loadCronTasksList(ctx, PAGE, resultLimit);
}, 500));
@@ -62,26 +65,19 @@ public class AdminCronTasksActivity extends BaseActivity {
private void fetchDataAsync(Context ctx) {
- AdminCronTasksViewModel cronTasksViewModel = new ViewModelProvider(this).get(AdminCronTasksViewModel.class);
-
- cronTasksViewModel.getCronTasksList(ctx, PAGE, LIMIT).observe(this, cronTasksListMain -> {
+ adminCronTasksViewModel.getCronTasksList(ctx, PAGE, resultLimit).observe(this, cronTasksListMain -> {
adapter = new AdminCronTasksAdapter(cronTasksListMain);
if(adapter.getItemCount() > 0) {
-
- activityAdminCronTasksBinding.recyclerView.setVisibility(View.VISIBLE);
activityAdminCronTasksBinding.recyclerView.setAdapter(adapter);
activityAdminCronTasksBinding.noData.setVisibility(View.GONE);
+ activityAdminCronTasksBinding.progressBar.setVisibility(View.GONE);
}
else {
-
- activityAdminCronTasksBinding.recyclerView.setVisibility(View.GONE);
activityAdminCronTasksBinding.noData.setVisibility(View.VISIBLE);
}
-
});
-
}
private void initCloseListener() {
diff --git a/app/src/main/java/org/mian/gitnex/activities/AdminUnadoptedReposActivity.java b/app/src/main/java/org/mian/gitnex/activities/AdminUnadoptedReposActivity.java
new file mode 100644
index 00000000..b297ef2c
--- /dev/null
+++ b/app/src/main/java/org/mian/gitnex/activities/AdminUnadoptedReposActivity.java
@@ -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();
+ }
+}
diff --git a/app/src/main/java/org/mian/gitnex/adapters/AdminUnadoptedReposAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/AdminUnadoptedReposAdapter.java
new file mode 100644
index 00000000..060b7b2e
--- /dev/null
+++ b/app/src/main/java/org/mian/gitnex/adapters/AdminUnadoptedReposAdapter.java
@@ -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 {
+
+ private List 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 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 call = RetrofitClient
+ .getApiInterface(ctx)
+ .adminDeleteUnadoptedRepository(repoSplit[0], repoSplit[1]);
+
+ call.enqueue(new Callback<>() {
+
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull retrofit2.Response 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 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 call = RetrofitClient
+ .getApiInterface(ctx)
+ .adminAdoptRepository(repoSplit[0], repoSplit[1]);
+
+ call.enqueue(new Callback<>() {
+
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull retrofit2.Response 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 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 list) {
+ this.repos = list;
+ notifyDataSetChanged();
+ }
+
+ public void setHasMore(boolean hasMore) {
+ this.hasMore = hasMore;
+ isLoading = false;
+ }
+}
diff --git a/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java
index e6c68030..5cc1defb 100644
--- a/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java
+++ b/app/src/main/java/org/mian/gitnex/adapters/LabelsAdapter.java
@@ -52,7 +52,7 @@ public class LabelsAdapter extends RecyclerView.Adapter {
diff --git a/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java
index f89ec84e..c93b694e 100644
--- a/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java
+++ b/app/src/main/java/org/mian/gitnex/adapters/UserSearchForTeamMemberAdapter.java
@@ -9,11 +9,9 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.v2.models.User;
import org.mian.gitnex.R;
-import org.mian.gitnex.actions.TeamActions;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.clients.PicassoService;
diff --git a/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java b/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java
index 0cd5a943..213249f8 100644
--- a/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java
+++ b/app/src/main/java/org/mian/gitnex/fragments/AdministrationFragment.java
@@ -1,6 +1,5 @@
package org.mian.gitnex.fragments;
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
@@ -11,29 +10,30 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.mian.gitnex.activities.AdminCronTasksActivity;
import org.mian.gitnex.activities.AdminGetUsersActivity;
+import org.mian.gitnex.activities.AdminUnadoptedReposActivity;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.databinding.FragmentAdministrationBinding;
/**
- * Author M M Arif
+ * @author M M Arif
*/
public class AdministrationFragment extends Fragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- Context ctx = getContext();
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(((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");
if(action != null) {
diff --git a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java
index 5339382a..1f60cdd6 100644
--- a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java
+++ b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java
@@ -45,7 +45,11 @@ import java.util.Objects;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
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
diff --git a/app/src/main/java/org/mian/gitnex/helpers/TinyDB.java b/app/src/main/java/org/mian/gitnex/helpers/TinyDB.java
index 8d01a05a..c5e52340 100644
--- a/app/src/main/java/org/mian/gitnex/helpers/TinyDB.java
+++ b/app/src/main/java/org/mian/gitnex/helpers/TinyDB.java
@@ -5,12 +5,9 @@ import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.os.Environment;
-import android.text.TextUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Map;
public class TinyDB {
diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/AdminUnadoptedReposViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/AdminUnadoptedReposViewModel.java
new file mode 100644
index 00000000..fa9d434d
--- /dev/null
+++ b/app/src/main/java/org/mian/gitnex/viewmodels/AdminUnadoptedReposViewModel.java
@@ -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> tasksList;
+
+ public LiveData> 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> call = RetrofitClient
+ .getApiInterface(ctx)
+ .adminUnadoptedList(page, limit, query);
+
+ call.enqueue(new Callback<>() {
+
+ @Override
+ public void onResponse(@NonNull Call> call, @NonNull Response> response) {
+
+ if(response.isSuccessful()) {
+ if(page <= 1 || tasksList.getValue() == null) {
+ tasksList.postValue(response.body());
+ } else {
+ List 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> call, @NonNull Throwable t) {
+
+ Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
+ }
+ });
+ }
+}
diff --git a/app/src/main/res/layout/activity_admin_cron_tasks.xml b/app/src/main/res/layout/activity_admin_cron_tasks.xml
index a5592d87..92f67c41 100644
--- a/app/src/main/res/layout/activity_admin_cron_tasks.xml
+++ b/app/src/main/res/layout/activity_admin_cron_tasks.xml
@@ -1,5 +1,5 @@
-
+
+
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/progress_bar">
+ android:visibility="gone" />
-
+
diff --git a/app/src/main/res/layout/fragment_administration.xml b/app/src/main/res/layout/fragment_administration.xml
index d7f651aa..d3806d3c 100644
--- a/app/src/main/res/layout/fragment_administration.xml
+++ b/app/src/main/res/layout/fragment_administration.xml
@@ -11,21 +11,51 @@
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
-
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:padding="16dp">
+
+
+
+
+
+
+
+
+
+
+
+
-
+ android:gravity="center_vertical"
+ android:orientation="horizontal"
+ android:padding="16dp">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_admin_unadopted_repos.xml b/app/src/main/res/layout/list_admin_unadopted_repos.xml
new file mode 100644
index 00000000..2834afad
--- /dev/null
+++ b/app/src/main/res/layout/list_admin_unadopted_repos.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c404cd97..bfc70ca6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -762,4 +762,8 @@
Follow system (Light/Dark)
Follow system (Light/Pitch Black)
Fork of: %s
+ Adopt
+ Adopted repository %s
+ Unadopted Repositories
+ - Adopt will add repository %s to organization/user %s.\n- Delete will remove it from the system.
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 672454ac..69007921 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -247,6 +247,7 @@