diff --git a/app/build.gradle b/app/build.gradle index 6eb725c5..2903e0c0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -109,7 +109,7 @@ dependencies { implementation "androidx.work:work-runtime:$work_version" implementation "io.mikael:urlbuilder:2.0.9" implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2" - implementation "org.codeberg.gitnex:tea4j:1.1.3" + implementation "org.codeberg.gitnex:tea4j:1.1.4" coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" implementation 'androidx.biometric:biometric:1.1.0' implementation 'com.github.chrisvest:stormpot:2.4.2' diff --git a/app/src/main/java/org/mian/gitnex/activities/AdminGetUsersActivity.java b/app/src/main/java/org/mian/gitnex/activities/AdminGetUsersActivity.java index 9a6ab974..b7af53e3 100644 --- a/app/src/main/java/org/mian/gitnex/activities/AdminGetUsersActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/AdminGetUsersActivity.java @@ -1,6 +1,5 @@ package org.mian.gitnex.activities; -import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; @@ -10,96 +9,101 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.EditorInfo; -import android.widget.ImageView; -import android.widget.TextView; import androidx.appcompat.widget.SearchView; import androidx.appcompat.widget.Toolbar; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.mian.gitnex.R; import org.mian.gitnex.adapters.AdminGetUsersAdapter; -import org.mian.gitnex.databinding.ActivityAdminGetUsersBinding; import org.mian.gitnex.fragments.BottomSheetAdminUsersFragment; import org.mian.gitnex.helpers.AppUtil; +import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.structs.BottomSheetListener; import org.mian.gitnex.viewmodels.AdminGetUsersViewModel; +import org.mian.gitnex.databinding.ActivityAdminGetUsersBinding; /** - * Author M M Arif + * @author M M Arif */ public class AdminGetUsersActivity extends BaseActivity implements BottomSheetListener { - private View.OnClickListener onClickListener; - private AdminGetUsersAdapter adapter; - private RecyclerView mRecyclerView; - private TextView noDataUsers; - private Boolean searchFilter = false; + private View.OnClickListener onClickListener; + private ActivityAdminGetUsersBinding activityAdminGetUsersBinding; + private AdminGetUsersAdapter adapter; + private int page = 1; + private int resultLimit = Constants.resultLimitNewGiteaInstances; + private Boolean searchFilter = false; - @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + super.onCreate(savedInstanceState); - ActivityAdminGetUsersBinding activityAdminGetUsersBinding = ActivityAdminGetUsersBinding.inflate(getLayoutInflater()); - setContentView(activityAdminGetUsersBinding.getRoot()); + activityAdminGetUsersBinding = ActivityAdminGetUsersBinding.inflate(getLayoutInflater()); + setContentView(activityAdminGetUsersBinding.getRoot()); - ImageView closeActivity = activityAdminGetUsersBinding.close; - noDataUsers = activityAdminGetUsersBinding.noDataUsers; - mRecyclerView = activityAdminGetUsersBinding.recyclerView; + Toolbar toolbar = activityAdminGetUsersBinding.toolbar; + setSupportActionBar(toolbar); - final SwipeRefreshLayout swipeRefresh = activityAdminGetUsersBinding.pullToRefresh; + initCloseListener(); + activityAdminGetUsersBinding.close.setOnClickListener(onClickListener); - Toolbar toolbar = activityAdminGetUsersBinding.toolbar; - setSupportActionBar(toolbar); + activityAdminGetUsersBinding.recyclerView.setHasFixedSize(true); + activityAdminGetUsersBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx)); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(activityAdminGetUsersBinding.recyclerView.getContext(), + DividerItemDecoration.VERTICAL); + activityAdminGetUsersBinding.recyclerView.addItemDecoration(dividerItemDecoration); - initCloseListener(); - closeActivity.setOnClickListener(onClickListener); + activityAdminGetUsersBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { - mRecyclerView.setHasFixedSize(true); - mRecyclerView.setLayoutManager(new LinearLayoutManager(ctx)); + page = 1; + activityAdminGetUsersBinding.pullToRefresh.setRefreshing(false); + fetchDataAsync(getAccount().getAuthorization()); + activityAdminGetUsersBinding.progressBar.setVisibility(View.VISIBLE); + }, 50)); - DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), - DividerItemDecoration.VERTICAL); - mRecyclerView.addItemDecoration(dividerItemDecoration); + fetchDataAsync(getAccount().getAuthorization()); + }; - swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + private void fetchDataAsync(String instanceToken) { - swipeRefresh.setRefreshing(false); - AdminGetUsersViewModel.loadUsersList(ctx, getAccount().getAuthorization()); + AdminGetUsersViewModel adminUsersModel = new ViewModelProvider(this).get(AdminGetUsersViewModel.class); - }, 500)); + adminUsersModel.getUsersList(instanceToken, page, resultLimit, ctx).observe(this, adminUsersListMain -> { - fetchDataAsync(ctx, getAccount().getAuthorization()); + adapter = new AdminGetUsersAdapter(adminUsersListMain, ctx); + adapter.setLoadMoreListener(new AdminGetUsersAdapter.OnLoadMoreListener() { - } + @Override + public void onLoadMore() { - private void fetchDataAsync(Context ctx, String instanceToken) { + page += 1; + AdminGetUsersViewModel.loadMoreUsersList(instanceToken, page, resultLimit, ctx, adapter); + activityAdminGetUsersBinding.progressBar.setVisibility(View.VISIBLE); + } - AdminGetUsersViewModel usersModel = new ViewModelProvider(this).get(AdminGetUsersViewModel.class); + @Override + public void onLoadFinished() { - usersModel.getUsersList(ctx, instanceToken).observe(this, usersListMain -> { + activityAdminGetUsersBinding.progressBar.setVisibility(View.GONE); + } + }); - adapter = new AdminGetUsersAdapter(ctx, usersListMain); - if(adapter.getItemCount() > 0) { + if(adapter.getItemCount() > 0) { + activityAdminGetUsersBinding.recyclerView.setAdapter(adapter); + activityAdminGetUsersBinding.noDataUsers.setVisibility(View.GONE); + searchFilter = true; + } + else { + adapter.notifyDataChanged(); + activityAdminGetUsersBinding.recyclerView.setAdapter(adapter); + activityAdminGetUsersBinding.noDataUsers.setVisibility(View.VISIBLE); + } - mRecyclerView.setVisibility(View.VISIBLE); - mRecyclerView.setAdapter(adapter); - noDataUsers.setVisibility(View.GONE); - searchFilter = true; - } - else { - - mRecyclerView.setVisibility(View.GONE); - noDataUsers.setVisibility(View.VISIBLE); - } - - }); - - } + activityAdminGetUsersBinding.progressBar.setVisibility(View.GONE); + }); + } @Override public boolean onCreateOptionsMenu(final Menu menu) { @@ -134,10 +138,8 @@ public class AdminGetUsersActivity extends BaseActivity implements BottomSheetLi adapter.getFilter().filter(newText); return false; } - }); } - }, 500); return true; @@ -168,16 +170,12 @@ public class AdminGetUsersActivity extends BaseActivity implements BottomSheetLi @Override public void onButtonClicked(String text) { - switch (text) { - case "newUser": - startActivity(new Intent(AdminGetUsersActivity.this, CreateNewUserActivity.class)); - break; - } - + if("newUser".equals(text)) { + startActivity(new Intent(AdminGetUsersActivity.this, CreateNewUserActivity.class)); + } } private void initCloseListener() { onClickListener = view -> finish(); } - } diff --git a/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java index c4f63d55..dabf9ea7 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/AdminGetUsersAdapter.java @@ -1,5 +1,6 @@ package org.mian.gitnex.adapters; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.text.Html; @@ -24,116 +25,167 @@ import java.util.ArrayList; import java.util.List; /** - * Author M M Arif + * @author M M Arif */ -public class AdminGetUsersAdapter extends RecyclerView.Adapter implements Filterable { +public class AdminGetUsersAdapter extends RecyclerView.Adapter implements Filterable { - private final List usersList; - private final Context context; - private final List usersListFull; + private List usersList; + private final List usersListFull; + private final Context context; + private final int TYPE_LOAD = 0; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; - class UsersViewHolder extends RecyclerView.ViewHolder { + public AdminGetUsersAdapter(List usersListMain, Context ctx) { + this.context = ctx; + this.usersList = usersListMain; + usersListFull = new ArrayList<>(usersList); + } - private String userLoginId; + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if(viewType == TYPE_LOAD) { + return new AdminGetUsersAdapter.ReposHolder(inflater.inflate(R.layout.list_admin_users, parent, false)); + } + else { + return new AdminGetUsersAdapter.LoadHolder(inflater.inflate(R.layout.row_load, parent, false)); + } + } - private final ImageView userAvatar; - private final TextView userFullName; - private final TextView userEmail; - private final ImageView userRole; - private final TextView userName; + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } - private UsersViewHolder(View itemView) { + if(getItemViewType(position) == TYPE_LOAD) { + ((AdminGetUsersAdapter.ReposHolder) holder).bindData(usersList.get(position)); + } + } - super(itemView); + @Override + public int getItemViewType(int position) { + if(usersList.get(position).getFullname() != null) { + return TYPE_LOAD; + } + else { + return 1; + } + } - userAvatar = itemView.findViewById(R.id.userAvatar); - userFullName = itemView.findViewById(R.id.userFullName); - userName = itemView.findViewById(R.id.userName); - userEmail = itemView.findViewById(R.id.userEmail); - userRole = itemView.findViewById(R.id.userRole); + @Override + public int getItemCount() { + return usersList.size(); + } - itemView.setOnClickListener(loginId -> { - Intent intent = new Intent(context, ProfileActivity.class); - intent.putExtra("username", userLoginId); - context.startActivity(intent); - }); + class ReposHolder extends RecyclerView.ViewHolder { - userAvatar.setOnLongClickListener(loginId -> { - AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); - return true; - }); - } - } + private String userLoginId; + private final ImageView userAvatar; + private final TextView userFullName; + private final TextView userEmail; + private final ImageView userRole; + private final TextView userName; - public AdminGetUsersAdapter(Context ctx, List usersListMain) { + ReposHolder(View itemView) { - this.context = ctx; - this.usersList = usersListMain; - usersListFull = new ArrayList<>(usersList); - } + super(itemView); + userAvatar = itemView.findViewById(R.id.userAvatar); + userFullName = itemView.findViewById(R.id.userFullName); + userName = itemView.findViewById(R.id.userName); + userEmail = itemView.findViewById(R.id.userEmail); + userRole = itemView.findViewById(R.id.userRole); - @NonNull - @Override - public AdminGetUsersAdapter.UsersViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + itemView.setOnClickListener(loginId -> { + Intent intent = new Intent(context, ProfileActivity.class); + intent.putExtra("username", userLoginId); + context.startActivity(intent); + }); - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_admin_users, parent, false); - return new AdminGetUsersAdapter.UsersViewHolder(v); - } + userAvatar.setOnLongClickListener(loginId -> { + AppUtil.copyToClipboard(context, userLoginId, context.getString(R.string.copyLoginIdToClipBoard, userLoginId)); + return true; + }); + } - @Override - public void onBindViewHolder(@NonNull AdminGetUsersAdapter.UsersViewHolder holder, int position) { + void bindData(UserInfo users) { - UserInfo currentItem = usersList.get(position); - int imgRadius = AppUtil.getPixelsFromDensity(context, 3); + int imgRadius = AppUtil.getPixelsFromDensity(context, 3); - holder.userLoginId = currentItem.getLogin(); + userLoginId = users.getLogin(); - if(!currentItem.getFullname().equals("")) { + if(!users.getFullname().equals("")) { - holder.userFullName.setText(Html.fromHtml(currentItem.getFullname())); - holder.userName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername())); - } - else { + userFullName.setText(Html.fromHtml(users.getFullname())); + userName.setText(context.getResources().getString(R.string.usernameWithAt, users.getUsername())); + } + else { - holder.userFullName.setText(context.getResources().getString(R.string.usernameWithAt, currentItem.getUsername())); - holder.userName.setVisibility(View.GONE); - } + userFullName.setText(context.getResources().getString(R.string.usernameWithAt, users.getUsername())); + userName.setVisibility(View.GONE); + } - if(!currentItem.getEmail().equals("")) { + if(!users.getEmail().equals("")) { + userEmail.setText(users.getEmail()); + } + else { + userEmail.setVisibility(View.GONE); + } - holder.userEmail.setText(currentItem.getEmail()); - } - else { + if(users.getIs_admin()) { - holder.userEmail.setVisibility(View.GONE); - } + userRole.setVisibility(View.VISIBLE); + TextDrawable drawable = TextDrawable.builder().beginConfig() + .textColor(ResourcesCompat.getColor(context.getResources(), R.color.colorWhite, null)).fontSize(44).width(180).height(60) + .endConfig().buildRoundRect(context.getResources().getString(R.string.userRoleAdmin).toLowerCase(), ResourcesCompat.getColor(context.getResources(), R.color.releasePre, null), 8); + userRole.setImageDrawable(drawable); + } + else { - if(currentItem.getIs_admin()) { + userRole.setVisibility(View.GONE); + } - holder.userRole.setVisibility(View.VISIBLE); - TextDrawable drawable = TextDrawable.builder() - .beginConfig() - .textColor(ResourcesCompat.getColor(context.getResources(), R.color.colorWhite, null)) - .fontSize(44) - .width(180) - .height(60) - .endConfig() - .buildRoundRect(context.getResources().getString(R.string.userRoleAdmin).toLowerCase(), ResourcesCompat.getColor(context.getResources(), R.color.releasePre, null), 8); - holder.userRole.setImageDrawable(drawable); - } - else { + PicassoService.getInstance(context).get().load(users.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(userAvatar); + } + } - holder.userRole.setVisibility(View.GONE); - } + static class LoadHolder extends RecyclerView.ViewHolder { + LoadHolder(View itemView) { + super(itemView); + } + } - PicassoService.getInstance(context).get().load(currentItem.getAvatar()).placeholder(R.drawable.loader_animated).transform(new RoundedTransformation(imgRadius, 0)).resize(120, 120).centerCrop().into(holder.userAvatar); - } + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + if(!isMoreDataAvailable) { + loadMoreListener.onLoadFinished(); + } + } - @Override - public int getItemCount() { - return usersList.size(); - } + @SuppressLint("NotifyDataSetChanged") + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + loadMoreListener.onLoadFinished(); + } + + public interface OnLoadMoreListener { + void onLoadMore(); + void onLoadFinished(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + usersList = list; + notifyDataChanged(); + } @Override public Filter getFilter() { @@ -169,8 +221,7 @@ public class AdminGetUsersAdapter extends RecyclerView.Adapter 0) { fragmentRepositoriesBinding.recyclerView.setAdapter(adapter); fragmentRepositoriesBinding.noData.setVisibility(View.GONE); diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/AdminGetUsersViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/AdminGetUsersViewModel.java index 5e005409..afa970f0 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/AdminGetUsersViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/AdminGetUsersViewModel.java @@ -7,79 +7,88 @@ import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; import org.gitnex.tea4j.models.UserInfo; -import org.mian.gitnex.R; +import org.mian.gitnex.adapters.AdminGetUsersAdapter; import org.mian.gitnex.clients.RetrofitClient; -import org.mian.gitnex.helpers.AlertDialogs; -import org.mian.gitnex.helpers.Toasty; import java.util.List; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; /** - * Author M M Arif + * @author M M Arif */ public class AdminGetUsersViewModel extends ViewModel { private static MutableLiveData> usersList; - public LiveData> getUsersList(Context ctx, String token) { + public LiveData> getUsersList(String token, int page, int resultLimit, Context ctx) { usersList = new MutableLiveData<>(); - loadUsersList(ctx, token); + loadUsersList(token, page, resultLimit, ctx); return usersList; } - public static void loadUsersList(final Context ctx, String token) { + public static void loadUsersList(String token, int page, int resultLimit, Context ctx) { Call> call = RetrofitClient .getApiInterface(ctx) - .adminGetUsers(token); + .adminGetUsers(token, page, resultLimit); call.enqueue(new Callback>() { @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { - if (response.code() == 200) { - usersList.postValue(response.body()); - } - - else if(response.code() == 401) { - - AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle), - ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage), - ctx.getResources().getString(R.string.cancelButton), - ctx.getResources().getString(R.string.navLogout)); - - } - 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)); - Log.i("onResponse", String.valueOf(response.code())); - - } - + if (response.isSuccessful()) { + if(response.code() == 200) { + usersList.postValue(response.body()); + } + } } @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { - Log.i("onFailure", t.toString()); + Log.e("onFailure", t.toString()); } }); } + public static void loadMoreUsersList(String token, int page, int resultLimit, Context ctx, AdminGetUsersAdapter adapter) { + + Call> call = RetrofitClient + .getApiInterface(ctx) + .adminGetUsers(token, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if (response.isSuccessful()) { + List list = usersList.getValue(); + assert list != null; + assert response.body() != null; + + if(response.body().size() != 0) { + list.addAll(response.body()); + adapter.updateList(list); + } + else { + adapter.setMoreDataAvailable(false); + } + } + else { + Log.e("onResponse", String.valueOf(response.code())); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.e("onFailure", t.toString()); + } + }); + } } 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 c3b27ec3..c070da0e 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/RepositoriesViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/RepositoriesViewModel.java @@ -57,7 +57,6 @@ public class RepositoriesViewModel extends ViewModel { if(response.isSuccessful()) { if(response.code() == 200) { reposList.postValue(response.body()); - Log.e("typeRepo", String.valueOf(reposList)); } } } diff --git a/app/src/main/res/layout/activity_admin_get_users.xml b/app/src/main/res/layout/activity_admin_get_users.xml index 5224afc4..171efa5e 100644 --- a/app/src/main/res/layout/activity_admin_get_users.xml +++ b/app/src/main/res/layout/activity_admin_get_users.xml @@ -1,11 +1,10 @@ - + android:orientation="vertical" + android:background="?attr/primaryBackgroundColor"> + android:ellipsize="none" + android:scrollbars="horizontal" + android:singleLine="true" + android:layout_marginEnd="20dp" + android:textSize="18sp" /> + + + android:visibility="gone" /> - + diff --git a/app/src/main/res/layout/list_admin_users.xml b/app/src/main/res/layout/list_admin_users.xml index 4142d603..b001bff8 100644 --- a/app/src/main/res/layout/list_admin_users.xml +++ b/app/src/main/res/layout/list_admin_users.xml @@ -4,7 +4,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" - android:background="?attr/primaryBackgroundColor" > + android:background="?android:attr/selectableItemBackground">